home *** CD-ROM | disk | FTP | other *** search
/ PC Open 107 / PC Open 107 CD 1.bin / CD1 / INTERNET / COPIA SITI / Getleft / getleft-setup-notcl.exe / {app} / scripts / tablelistWidget.tcl < prev    next >
Encoding:
Text File  |  2004-03-11  |  74.4 KB  |  2,803 lines

  1. #==============================================================================
  2. # Contains the implementation of the tablelist widget.
  3. #
  4. # Structure of the module:
  5. #   - Namespace initialization
  6. #   - Public procedure
  7. #   - Private configuration procedures
  8. #   - Private procedures implementing the tablelist widget command
  9. #   - Private callback procedures
  10. #   - Private procedures used in bindings
  11. #   - Private utility procedures
  12. #
  13. # Copyright (c) 2000-2004  Csaba Nemethi (E-mail: csaba.nemethi@t-online.de)
  14. #==============================================================================
  15.  
  16. #
  17. # Namespace initialization
  18. # ========================
  19. #
  20. namespace eval tablelist {
  21.     #
  22.     # The array configSpecs is used to handle configuration options.  The
  23.     # names of its elements are the configuration options for the Tablelist
  24.     # class.  The value of an array element is either an alias name or a list
  25.     # containing the database name and class as well as an indicator specifying
  26.     # the widget(s) to which the option applies: c stands for all children
  27.     # (text widgets and labels), b for the body text widget, h for the header
  28.     # text widget, l for the labels, f for the frame, and w for the widget
  29.     # itself.
  30.     #
  31.     #    Command-Line Name     {Database Name          Database Class      W}
  32.     #    ------------------------------------------------------------------------
  33.     #
  34.     variable configSpecs
  35.     array set configSpecs {
  36.     -activestyle         {activeStyle          ActiveStyle          w}
  37.     -arrowcolor         {arrowColor          ArrowColor          w}
  38.     -arrowdisabledcolor     {arrowDisabledColor      ArrowDisabledColor  w}
  39.     -background         {background          Background          b}
  40.     -bg             -background
  41.     -borderwidth         {borderWidth          BorderWidth          f}
  42.     -bd             -borderwidth
  43.     -columns         {columns          Columns          w}
  44.     -cursor             {cursor          Cursor          c}
  45.     -disabledforeground     {disabledForeground      DisabledForeground  w}
  46.     -editendcommand         {editEndCommand      EditEndCommand      w}
  47.     -editstartcommand     {editStartCommand      EditStartCommand    w}
  48.     -exportselection     {exportSelection      ExportSelection     w}
  49.     -font             {font              Font              b}
  50.     -foreground         {foreground          Foreground          b}
  51.     -fg             -foreground
  52.     -height             {height          Height          w}
  53.     -highlightbackground     {highlightBackground      HighlightBackground f}
  54.     -highlightcolor         {highlightColor      HighlightColor      f}
  55.     -highlightthickness     {highlightThickness      HighlightThickness  f}
  56.     -incrarrowtype         {incrArrowType          IncrArrowType          w}
  57.     -labelbackground     {labelBackground      Background          l}
  58.     -labelbg         -labelbackground
  59.     -labelborderwidth     {labelBorderWidth      BorderWidth          l}
  60.     -labelbd         -labelborderwidth
  61.     -labelcommand         {labelCommand          LabelCommand          w}
  62.     -labeldisabledforeground {labelDisabledForeground DisabledForeground  l}
  63.     -labelfont         {labelFont          Font              l}
  64.     -labelforeground     {labelForeground      Foreground          l}
  65.     -labelfg         -labelforeground
  66.     -labelheight         {labelHeight          Height          l}
  67.     -labelpady         {labelPadY          Pad              l}
  68.     -labelrelief         {labelRelief          Relief          l}
  69.     -listvariable         {listVariable          Variable          w}
  70.     -movablecolumns          {movableColumns      MovableColumns      w}
  71.     -movecolumncursor     {moveColumnCursor      MoveColumnCursor    w}
  72.     -relief             {relief          Relief          f}
  73.     -resizablecolumns     {resizableColumns      ResizableColumns    w}
  74.     -resizecursor         {resizeCursor          ResizeCursor          w}
  75.     -selectbackground     {selectBackground      Foreground          w}
  76.     -selectborderwidth     {selectBorderWidth      BorderWidth          w}
  77.     -selectforeground     {selectForeground      Background          w}
  78.     -selectmode         {selectMode          SelectMode          w}
  79.     -setgrid         {setGrid          SetGrid          w}
  80.     -showarrow         {showArrow          ShowArrow          w}
  81.     -showlabels         {showLabels          ShowLabels          w}
  82.     -showseparators         {showSeparators      ShowSeparators      w}
  83.     -snipstring         {snipString          SnipString          w}
  84.     -sortcommand         {sortCommand          SortCommand          w}
  85.     -state             {state              State              w}
  86.     -stretch         {stretch          Stretch          w}
  87.     -stripebackground     {stripeBackground      Background          w}
  88.     -stripebg         -stripebackground
  89.     -stripeforeground     {stripeForeground      Foreground          w}
  90.     -stripefg         -stripeforeground
  91.     -stripeheight         {stripeHeight          StripeHeight          w}
  92.     -takefocus         {takeFocus          TakeFocus          f}
  93.     -targetcolor         {targetColor          TargetColor          w}
  94.     -width             {width              Width              w}
  95.     -xscrollcommand         {xScrollCommand      ScrollCommand          h}
  96.     -yscrollcommand         {yScrollCommand      ScrollCommand          b}
  97.     }
  98.  
  99.     #
  100.     # Get the current windowing system ("x11", "win32", "classic", or "aqua")
  101.     #
  102.     variable winSys
  103.     if {[catch {tk windowingsystem} winSys] != 0} {
  104.     switch $::tcl_platform(platform) {
  105.         unix    { set winSys x11 }
  106.         windows    { set winSys win32 }
  107.         macintosh    { set winSys classic }
  108.     }
  109.     }
  110.  
  111.     #
  112.     # Extend the elements of the array configSpecs
  113.     #
  114.     extendConfigSpecs 
  115.  
  116.     variable configOpts [lsort [array names configSpecs]]
  117.  
  118.     #
  119.     # The array colConfigSpecs is used to handle column configuration options.
  120.     # The names of its elements are the column configuration options for the
  121.     # Tablelist widget class.  The value of an array element is either an alias
  122.     # name or a list containing the database name and class.
  123.     #
  124.     #    Command-Line Name    {Database Name        Database Class    }
  125.     #    -----------------------------------------------------------------
  126.     #
  127.     variable colConfigSpecs
  128.     array set colConfigSpecs {
  129.     -align            {align            Align        }
  130.     -background        {background        Background    }
  131.     -bg            -background
  132.     -editable        {editable        Editable    }
  133.     -editwindow        {editWindow        EditWindow    }
  134.     -font            {font            Font        }
  135.     -foreground        {foreground        Foreground    }
  136.     -fg            -foreground
  137.     -formatcommand        {formatCommand        FormatCommand    }
  138.     -hide            {hide            Hide        }
  139.     -labelalign        {labelAlign        Align        }
  140.     -labelbackground    {labelBackground    Background    }
  141.     -labelbg        -labelbackground
  142.     -labelborderwidth    {labelBorderWidth    BorderWidth    }
  143.     -labelbd        -labelborderwidth
  144.     -labelcommand        {labelCommand        LabelCommand    }
  145.     -labelfont        {labelFont        Font        }
  146.     -labelforeground    {labelForeground    Foreground    }
  147.     -labelfg        -labelforeground
  148.     -labelheight        {labelHeight        Height        }
  149.     -labelimage        {labelImage        Image        }
  150.     -labelpady        {labelPadY        Pad        }
  151.     -labelrelief        {labelRelief        Relief        }
  152.     -maxwidth        {maxWidth        MaxWidth    }
  153.     -name            {name            Name        }
  154.     -resizable        {resizable        Resizable    }
  155.     -selectbackground    {selectBackground    Foreground    }
  156.     -selectforeground    {selectForeground    Background    }
  157.     -showarrow        {showArrow        ShowArrow    }
  158.     -sortcommand        {sortCommand        SortCommand    }
  159.     -sortmode        {sortMode        SortMode    }
  160.     -text            {text            Text        }
  161.     -title            {title            Title        }
  162.     -width            {width            Width        }
  163.     }
  164.  
  165.     #
  166.     # Extend some elements of the array colConfigSpecs
  167.     #
  168.     lappend colConfigSpecs(-align)    - left
  169.     lappend colConfigSpecs(-editable)    - 0
  170.     lappend colConfigSpecs(-editwindow)    - entry
  171.     lappend colConfigSpecs(-hide)    - 0
  172.     lappend colConfigSpecs(-maxwidth)    - 0
  173.     lappend colConfigSpecs(-resizable)    - 1
  174.     lappend colConfigSpecs(-showarrow)    - 1
  175.     lappend colConfigSpecs(-sortmode)    - ascii
  176.     lappend colConfigSpecs(-width)    - 0
  177.  
  178.     #
  179.     # The array rowConfigSpecs is used to handle row configuration options.
  180.     # The names of its elements are the row configuration options for the
  181.     # Tablelist widget class.  The value of an array element is either an alias
  182.     # name or a list containing the database name and class.
  183.     #
  184.     #    Command-Line Name    {Database Name        Database Class    }
  185.     #    -----------------------------------------------------------------
  186.     #
  187.     variable rowConfigSpecs
  188.     array set rowConfigSpecs {
  189.     -background        {background        Background    }
  190.     -bg            -background
  191.     -font            {font            Font        }
  192.     -foreground        {foreground        Foreground    }
  193.     -fg            -foreground
  194.     -selectable        {selectable        Selectable    }
  195.     -selectbackground    {selectBackground    Foreground    }
  196.     -selectforeground    {selectForeground    Background    }
  197.     -text            {text            Text        }
  198.     }
  199.  
  200.     #
  201.     # Extend some elements of the array rowConfigSpecs
  202.     #
  203.     lappend rowConfigSpecs(-selectable) - 1
  204.  
  205.     #
  206.     # The array cellConfigSpecs is used to handle cell configuration options.
  207.     # The names of its elements are the cell configuration options for the
  208.     # Tablelist widget class.  The value of an array element is either an alias
  209.     # name or a list containing the database name and class.
  210.     #
  211.     #    Command-Line Name    {Database Name        Database Class    }
  212.     #    -----------------------------------------------------------------
  213.     #
  214.     variable cellConfigSpecs
  215.     array set cellConfigSpecs {
  216.     -background        {background        Background    }
  217.     -bg            -background
  218.     -editable        {editable        Editable    }
  219.     -font            {font            Font        }
  220.     -foreground        {foreground        Foreground    }
  221.     -fg            -foreground
  222.     -image            {image            Image        }
  223.     -selectbackground    {selectBackground    Foreground    }
  224.     -selectforeground    {selectForeground    Background    }
  225.     -text            {text            Text        }
  226.     }
  227.  
  228.     #
  229.     # Extend some elements of the array cellConfigSpecs
  230.     #
  231.     lappend cellConfigSpecs(-editable) - 1
  232.  
  233.     #
  234.     # Use a list to facilitate the handling of the command options 
  235.     #
  236.     variable cmdOpts [list \
  237.     activate attrib bbox bodypath cancelediting cellcget cellconfigure \
  238.     cellindex cget columncget columnconfigure columncount columnindex \
  239.     configure containing containingcell containingcolumn curselection \
  240.     delete deletecolumns editcell editwinpath entrypath fillcolumn \
  241.     finishediting get getcolumns getkeys index insert insertcolumnlist \
  242.     insertcolumns insertlist labelpath labels move movecolumn nearest \
  243.     nearestcell nearestcolumn rejectinput resetsortinfo rowcget \
  244.     rowconfigure scan see seecell seecolumn selection separatorpath \
  245.     separators size sort sortbycolumn sortcolumn sortorder xview yview]
  246.  
  247.     #
  248.     # Use lists to facilitate the handling of miscellaneous options
  249.     #
  250.     variable activeStyles    [list frame none underline]
  251.     variable alignments        [list left right center]
  252.     variable arrowTypes        [list up down]
  253.     variable states        [list disabled normal]
  254.     variable sortModes        [list ascii command dictionary integer real]
  255.     variable sortOrders        [list -increasing -decreasing]
  256.     variable scanCmdOpts    [list mark dragto]
  257.     variable selCmdOpts        [list anchor clear includes set]
  258.  
  259.     #
  260.     # Define the procedure strToDispStr, which returns the string obtained
  261.     # by replacing all \t and \n characters in its argument with \\t and
  262.     # \\n, respectively, as well as the procedure strMap, needed because
  263.     # the "string map" command is not available in Tcl 8.0 and 8.1.0.
  264.     #
  265.     if {[catch {string map {} ""}] == 0} {
  266.     proc strToDispStr str {
  267.         if {[string first \t $str] >= 0 || [string first \n $str] >= 0} {
  268.         return [string map {\t \\t  \n \\n} $str]
  269.         } else {
  270.         return $str
  271.         }
  272.     }
  273.  
  274.     proc strMap {charMap str} {
  275.         return [string map $charMap $str]
  276.     }
  277.     } else {
  278.     proc strToDispStr str {
  279.         if {[string first \t $str] >= 0} {
  280.         regsub -all \t $str \\t str
  281.         }
  282.         if {[string first \n $str] >= 0} {
  283.         regsub -all \n $str \\n str
  284.         }
  285.  
  286.         return $str
  287.     }
  288.  
  289.     proc strMap {charMap str} {
  290.         foreach {key val} $charMap {
  291.         #
  292.         # We will only need this for noncritical key values
  293.         #
  294.         regsub -all $key $str $val str
  295.         }
  296.  
  297.         return $str
  298.     }
  299.     }
  300.  
  301.     #
  302.     # Define some Tablelist class bindings
  303.     #
  304.     bind Tablelist <KeyPress> continue
  305.     bind Tablelist <FocusIn> {
  306.     tablelist::addActiveTag %W
  307.  
  308.     if {[string compare [focus -lastfor %W] %W] == 0} {
  309.         if {[winfo exists [%W editwinpath]]} {
  310.         focus [set tablelist::ns%W::data(editFocus)]
  311.         } else {
  312.         focus [%W bodypath]
  313.         }
  314.     }
  315.     }
  316.     bind Tablelist <FocusOut> {
  317.     tablelist::removeActiveTag %W
  318.     }
  319.     bind Tablelist <Destroy> {
  320.     tablelist::cleanup %W
  321.     }
  322.  
  323.     #
  324.     # Define the binding tags TablelistKeyNav and TablelistBody
  325.     #
  326.     mwutil::defineKeyNav Tablelist
  327.     defineTablelistBody 
  328.  
  329.     #
  330.     # Define the virtual events <<Button3>> and <<ShiftButton3>>
  331.     #
  332.     event add <<Button3>> <Button-3>
  333.     event add <<ShiftButton3>> <Shift-Button-3>
  334.     if {[string compare $winSys classic] == 0 ||
  335.     [string compare $winSys aqua] == 0} {
  336.     event add <<Button3>> <Control-Button-1>
  337.     event add <<ShiftButton3>> <Shift-Control-Button-1>
  338.     }
  339.  
  340.     #
  341.     # Define some mouse bindings for the binding tag TablelistLabel
  342.     #
  343.     bind TablelistLabel <Enter>          { tablelist::labelEnter    %W %x }
  344.     bind TablelistLabel <Motion>      { tablelist::labelEnter    %W %x }
  345.     bind TablelistLabel <Button-1>      { tablelist::labelB1Down   %W %x }
  346.     bind TablelistLabel <B1-Motion>      { tablelist::labelB1Motion %W %x %y }
  347.     bind TablelistLabel <B1-Enter>      { tablelist::labelB1Enter  %W }
  348.     bind TablelistLabel <B1-Leave>      { tablelist::labelB1Leave  %W %x %y }
  349.     bind TablelistLabel <ButtonRelease-1> { tablelist::labelB1Up     %W %X}
  350.     bind TablelistLabel <<Button3>>      { tablelist::labelB3Down   %W }
  351.     bind TablelistLabel <<ShiftButton3>>  { tablelist::labelShiftB3Down %W }
  352.  
  353.     #
  354.     # Define the binding tags TablelistSubLabel and TablelistArrow
  355.     #
  356.     defineTablelistSubLabel 
  357.     defineTablelistArrow 
  358. }
  359.  
  360. #
  361. # Public procedure
  362. # ================
  363. #
  364.  
  365. #------------------------------------------------------------------------------
  366. # tablelist::tablelist
  367. #
  368. # Creates a new tablelist widget whose name is specified as the first command-
  369. # line argument, and configures it according to the options and their values
  370. # given on the command line.  Returns the name of the newly created widget.
  371. #------------------------------------------------------------------------------
  372. proc tablelist::tablelist args {
  373.     variable configSpecs
  374.     variable configOpts
  375.  
  376.     if {[llength $args] == 0} {
  377.     mwutil::wrongNumArgs "tablelist pathName ?options?"
  378.     }
  379.  
  380.     #
  381.     # Create a frame of the class Tablelist
  382.     #
  383.     set win [lindex $args 0]
  384.     if {[catch {
  385.     frame $win -class Tablelist -container 0 -height 0 -width 0
  386.     } result] != 0} {
  387.     return -code error $result
  388.     }
  389.  
  390.     #
  391.     # Create a namespace within the current one to hold the data of the widget
  392.     #
  393.     namespace eval ns$win {
  394.     #
  395.     # The folowing array holds various data for this widget
  396.     #
  397.     variable data
  398.     array set data {
  399.         hasListVar         0
  400.         isDisabled         0
  401.         ownsFocus         0
  402.         charWidth         1
  403.         hdrPixels         0
  404.         oldActiveIdx     0
  405.         activeIdx         0
  406.         anchorIdx         0
  407.         seqNum        -1
  408.         itemList         {}
  409.         itemCount         0
  410.         lastRow        -1
  411.         colList         {}
  412.         colCount         0
  413.         lastCol        -1
  414.         tagCount         0
  415.         imgCount         0
  416.         labelClicked     0
  417.         arrowCol        -1
  418.         sortCol        -1
  419.         sortOrder         {}
  420.         editRow        -1
  421.         editCol        -1
  422.         forceAdjust         0
  423.         fmtCmdFlagList     {}
  424.     }
  425.  
  426.     #
  427.     # The following array is used to hold arbitrary
  428.     # attributes and their values for this widget
  429.     #
  430.     variable attribVals
  431.     }
  432.  
  433.     #
  434.     # Initialize some further components of data
  435.     #
  436.     upvar ::tablelist::ns${win}::data data
  437.     foreach opt $configOpts {
  438.     set data($opt) [lindex $configSpecs($opt) 3]
  439.     }
  440.     set data(colFontList)    [list $data(-font)]
  441.     set data(listVarTraceCmd)    [list tablelist::listVarTrace $win]
  442.     set data(body)        $win.body
  443.     set data(bodyFr)        $data(body).f
  444.     set data(bodyFrEd)        $data(bodyFr).e
  445.     set data(hdr)        $win.hdr
  446.     set data(hdrTxt)        $data(hdr).t
  447.     set data(hdrTxtFr)        $data(hdrTxt).f
  448.     set data(hdrTxtFrCanv)    $data(hdrTxtFr).c
  449.     set data(hdrTxtFrLbl)    $data(hdrTxtFr).l
  450.     set data(hdrLbl)        $data(hdr).l
  451.     set data(hdrGap)        $data(hdr).g
  452.     set data(lb)        $win.lb
  453.     set data(sep)        $win.sep
  454.  
  455.     #
  456.     # Create a child hierarchy used to hold the column labels.  The
  457.     # labels will be created as children of the frame data(hdrTxtFr),
  458.     # which is embedded into the text widget data(hdrTxt) (in order
  459.     # to make it scrollable), which in turn fills the frame data(hdr)
  460.     # (whose width and height can be set arbitrarily in pixels).
  461.     #
  462.     set w $data(hdr)            ;# header frame
  463.     frame $w -borderwidth 0 -container 0 -height 0 -highlightthickness 0 \
  464.          -relief flat -takefocus 0 -width 0
  465.     bind $w <Configure> { tablelist::stretchColumnsWhenIdle [winfo parent %W] }
  466.     pack $w -fill x
  467.     set w $data(hdrTxt)            ;# text widget within the header frame
  468.     text $w -borderwidth 0 -highlightthickness 0 -insertwidth 0 \
  469.         -padx 0 -pady 0 -state normal -takefocus 0 -wrap none
  470.     place $w -relheight 1.0 -relwidth 1.0
  471.     bindtags $w [lreplace [bindtags $w] 1 1]
  472.     frame $data(hdrTxtFr) -borderwidth 0 -container 0 -height 0 \
  473.               -highlightthickness 0 -relief flat -takefocus 0 \
  474.               -width 0
  475.     $w window create 1.0 -window $data(hdrTxtFr)
  476.     label $data(hdrTxtFrLbl)0 
  477.     set w $data(hdrLbl)            ;# filler label within the header frame
  478.     label $w -bitmap "" -highlightthickness 0 -image "" -takefocus 0 \
  479.          -text "" -textvariable "" -underline -1 -wraplength 0
  480.     place $w -relheight 1.0 -relwidth 1.0
  481.  
  482.     #
  483.     # Create a canvas as a child of the frame data(hdrTxtFr),
  484.     # needed for displaying an up- or down-arrow when
  485.     # sorting the items by a column.   Set its width and
  486.     # height to temporary values and create two 3-D arrows
  487.     #
  488.     set w $data(hdrTxtFrCanv)
  489.     set size 9
  490.     canvas $w -borderwidth 0 -height $size -highlightthickness 0 \
  491.           -relief flat -takefocus 0 -width $size
  492.     create3DArrows $w
  493.  
  494.     #
  495.     # Replace the binding tag Canvas with TablelistArrow
  496.     # in the list of binding tags of the canvas
  497.     #
  498.     bindtags $w [lreplace [bindtags $w] 1 1 TablelistArrow]
  499.  
  500.     #
  501.     # Create a frame used to display a gap between two
  502.     # consecutive columns when moving a column interactively
  503.     #
  504.     frame $data(hdrGap) -borderwidth 1 -container 0 -highlightthickness 0 \
  505.             -relief sunken -takefocus 0 -width 4
  506.  
  507.     #
  508.     # Create the body text widget within the main frame
  509.     #
  510.     set w $data(body)
  511.     text $w -borderwidth 0 -exportselection 0 -highlightthickness 0 \
  512.         -insertwidth 0 -padx 0 -pady 0 -state normal -takefocus 0 -wrap none
  513.     bind $w <Configure> { tablelist::adjustSepsWhenIdle [winfo parent %W] }
  514.     pack $w -expand 1 -fill both
  515.  
  516.     #
  517.     # Modify the list of binding tags of the body text widget
  518.     #
  519.     bindtags $w [list $w TablelistBody [winfo toplevel $w] TablelistKeyNav all]
  520.  
  521.     #
  522.     # Create the "active", "stripe", "select", and "disabled" tags
  523.     # in the body text widget.  Don't use the built-in "sel" tag
  524.     # because on Windows the selection in a text widget only
  525.     # becomes visible when the window gets the input focus.
  526.     #
  527.     $w tag configure stripe -background "" -foreground ""
  528.     $w tag configure active -borderwidth 1 -underline 1
  529.     $w tag configure select -relief raised
  530.     $w tag configure disabled -underline 0
  531.  
  532.     #
  533.     # Create an unmanaged listbox child, used to handle the -setgrid option
  534.     #
  535.     listbox $data(lb)
  536.  
  537.     #
  538.     # Configure the widget according to the command-line
  539.     # arguments and to the available database options
  540.     #
  541.     if {[catch {
  542.     mwutil::configure $win configSpecs data tablelist::doConfig \
  543.               [lrange $args 1 end] 1
  544.     } result] != 0} {
  545.     destroy $win
  546.     return -code error $result
  547.     }
  548.  
  549.     #
  550.     # Move the original widget command into the current namespace
  551.     # and build a new widget procedure in the global one
  552.     #
  553.     rename ::$win $win
  554.     proc ::$win args [format {
  555.     if {[catch {tablelist::tablelistWidgetCmd %s $args} result] == 0} {
  556.         return $result
  557.     } else {
  558.         return -code error $result
  559.     }
  560.     } [list $win]]
  561.  
  562.     #
  563.     # Register a callback to be invoked whenever the PRIMARY selection is
  564.     # owned by the window win and someone attempts to retrieve it as a
  565.     # UTF8_STRING or STRING (the type UTF8_STRING is only needed to work
  566.     # around a bug in Tk 8.4.0 and 8.4.1 causing crashes under KDE 3.0)
  567.     #
  568.     selection handle -type UTF8_STRING $win \
  569.     [list ::tablelist::fetchSelection $win]
  570.     selection handle -type STRING $win \
  571.     [list ::tablelist::fetchSelection $win]
  572.  
  573.     #
  574.     # Set a trace on the array element data(activeIdx)
  575.     #
  576.     trace variable data(activeIdx) w [list tablelist::activeIdxTrace $win]
  577.  
  578.     return $win
  579. }
  580.  
  581. #
  582. # Private configuration procedures
  583. # ================================
  584. #
  585. # See the module "tablelistConfig.tcl"
  586. #
  587.  
  588. #
  589. # Private procedures implementing the tablelist widget command
  590. # ============================================================
  591. #
  592.  
  593. #------------------------------------------------------------------------------
  594. # tablelist::tablelistWidgetCmd
  595. #
  596. # This procedure is invoked to process the Tcl command corresponding to a
  597. # tablelist widget.
  598. #------------------------------------------------------------------------------
  599. proc tablelist::tablelistWidgetCmd {win argList} {
  600.     variable cmdOpts
  601.     upvar ::tablelist::ns${win}::data data
  602.  
  603.     set argCount [llength $argList]
  604.     if {$argCount == 0} {
  605.     mwutil::wrongNumArgs "$win option ?arg arg ...?"
  606.     }
  607.  
  608.     set cmd [mwutil::fullOpt "option" [lindex $argList 0] $cmdOpts]
  609.     switch $cmd {
  610.     activate -
  611.     bbox -
  612.     see {
  613.         if {$argCount != 2} {
  614.         mwutil::wrongNumArgs "$win $cmd index"
  615.         }
  616.  
  617.         synchronize $win
  618.         set index [rowIndex $win [lindex $argList 1] 0]
  619.         return [${cmd}SubCmd $win $index]
  620.     }
  621.  
  622.     attrib {
  623.         return [mwutil::attribSubCmd $win [lrange $argList 1 end]]
  624.     }
  625.  
  626.     bodypath {
  627.         if {$argCount != 1} {
  628.         mwutil::wrongNumArgs "$win $cmd"
  629.         }
  630.  
  631.         return $data(body)
  632.     }
  633.  
  634.     cancelediting -
  635.     curselection -
  636.     finishediting {
  637.         if {$argCount != 1} {
  638.         mwutil::wrongNumArgs "$win $cmd"
  639.         }
  640.  
  641.         synchronize $win
  642.         return [${cmd}SubCmd $win]
  643.     }
  644.  
  645.     cellcget {
  646.         if {$argCount != 3} {
  647.         mwutil::wrongNumArgs "$win $cmd cellIndex option"
  648.         }
  649.  
  650.         synchronize $win
  651.         scan [cellIndex $win [lindex $argList 1] 1] %d,%d row col
  652.         variable cellConfigSpecs
  653.         set opt [mwutil::fullConfigOpt [lindex $argList 2] cellConfigSpecs]
  654.         return [doCellCget $row $col $win $opt]
  655.     }
  656.  
  657.     cellconfigure {
  658.         if {$argCount < 2} {
  659.         mwutil::wrongNumArgs "$win $cmd cellIndex ?option? ?value?\
  660.                       ?option value ...?"
  661.         }
  662.  
  663.         synchronize $win
  664.         scan [cellIndex $win [lindex $argList 1] 1] %d,%d row col
  665.         variable cellConfigSpecs
  666.         set argList [lrange $argList 2 end]
  667.         mwutil::setConfigVals $win cellConfigSpecs cellConfigVals \
  668.                   "tablelist::doCellCget $row $col" $argList
  669.         return [mwutil::configSubCmd $win cellConfigSpecs cellConfigVals \
  670.             "tablelist::doCellConfig $row $col" $argList]
  671.     }
  672.  
  673.     cellindex {
  674.         if {$argCount != 2} {
  675.         mwutil::wrongNumArgs "$win $cmd cellIndex"
  676.         }
  677.  
  678.         synchronize $win
  679.         return [cellIndex $win [lindex $argList 1] 0]
  680.     }
  681.  
  682.     cget {
  683.         if {$argCount != 2} {
  684.         mwutil::wrongNumArgs "$win $cmd option"
  685.         }
  686.  
  687.         #
  688.         # Return the value of the specified configuration option
  689.         #
  690.         variable configSpecs
  691.         set opt [mwutil::fullConfigOpt [lindex $argList 1] configSpecs]
  692.         return $data($opt)
  693.     }
  694.  
  695.     columncget {
  696.         if {$argCount != 3} {
  697.         mwutil::wrongNumArgs "$win $cmd columnIndex option"
  698.         }
  699.  
  700.         synchronize $win
  701.         set col [colIndex $win [lindex $argList 1] 1]
  702.         variable colConfigSpecs
  703.         set opt [mwutil::fullConfigOpt [lindex $argList 2] colConfigSpecs]
  704.         return [doColCget $col $win $opt]
  705.     }
  706.  
  707.     columnconfigure {
  708.         if {$argCount < 2} {
  709.         mwutil::wrongNumArgs "$win $cmd columnIndex ?option? ?value?\
  710.                       ?option value ...?"
  711.         }
  712.  
  713.         synchronize $win
  714.         set col [colIndex $win [lindex $argList 1] 1]
  715.         variable colConfigSpecs
  716.         set argList [lrange $argList 2 end]
  717.         mwutil::setConfigVals $win colConfigSpecs colConfigVals \
  718.                   "tablelist::doColCget $col" $argList
  719.         return [mwutil::configSubCmd $win colConfigSpecs colConfigVals \
  720.             "tablelist::doColConfig $col" $argList]
  721.     }
  722.  
  723.     columncount {
  724.         if {$argCount != 1} {
  725.         mwutil::wrongNumArgs "$win $cmd"
  726.         }
  727.  
  728.         return $data(colCount)
  729.     }
  730.  
  731.     columnindex {
  732.         if {$argCount != 2} {
  733.         mwutil::wrongNumArgs "$win $cmd columnIndex"
  734.         }
  735.  
  736.         synchronize $win
  737.         return [colIndex $win [lindex $argList 1] 0]
  738.     }
  739.  
  740.     configure {
  741.         variable configSpecs
  742.         return [mwutil::configSubCmd $win configSpecs data \
  743.             tablelist::doConfig [lrange $argList 1 end]]
  744.     }
  745.  
  746.     containing {
  747.         if {$argCount != 2} {
  748.         mwutil::wrongNumArgs "$win $cmd y"
  749.         }
  750.  
  751.         set y [lindex $argList 1]
  752.         format %d $y        ;# integer check with error message
  753.         synchronize $win
  754.         return [containingSubCmd $win $y]
  755.     }
  756.  
  757.     containingcell {
  758.         if {$argCount != 3} {
  759.         mwutil::wrongNumArgs "$win $cmd x y"
  760.         }
  761.  
  762.         set x [lindex $argList 1]
  763.         format %d $x        ;# integer check with error message
  764.         set y [lindex $argList 2]
  765.         format %d $y        ;# integer check with error message
  766.         synchronize $win
  767.         return [containingSubCmd $win $y],[containingcolumnSubCmd $win $x]
  768.     }
  769.  
  770.     containingcolumn {
  771.         if {$argCount != 2} {
  772.         mwutil::wrongNumArgs "$win $cmd x"
  773.         }
  774.  
  775.         set x [lindex $argList 1]
  776.         format %d $x        ;# integer check with error message
  777.         synchronize $win
  778.         return [containingcolumnSubCmd $win $x]
  779.     }
  780.  
  781.     delete -
  782.     get -
  783.     getkeys {
  784.         if {$argCount < 2 || $argCount > 3} {
  785.         mwutil::wrongNumArgs "$win $cmd firstIndex lastIndex" \
  786.                      "$win $cmd indexList"
  787.         }
  788.  
  789.         synchronize $win
  790.         set first [lindex $argList 1]
  791.         if {$argCount == 3} {
  792.         set last [lindex $argList 2]
  793.         } else {
  794.         set last $first
  795.         }
  796.         incr argCount -1
  797.         return [${cmd}SubCmd $win $first $last $argCount]
  798.     }
  799.  
  800.     deletecolumns -
  801.     getcolumns {
  802.         if {$argCount < 2 || $argCount > 3} {
  803.         mwutil::wrongNumArgs "$win $cmd firstColumnIndex\
  804.                       lastColumnIndex" \
  805.                      "$win $cmd columnIndexList"
  806.         }
  807.  
  808.         synchronize $win
  809.         set first [lindex $argList 1]
  810.         if {$argCount == 3} {
  811.         set last [lindex $argList 2]
  812.         } else {
  813.         set last $first
  814.         }
  815.         incr argCount -1
  816.         return [${cmd}SubCmd $win $first $last $argCount]
  817.     }
  818.  
  819.     editcell {
  820.         if {$argCount != 2} {
  821.         mwutil::wrongNumArgs "$win $cmd cellIndex"
  822.         }
  823.  
  824.         synchronize $win
  825.         scan [cellIndex $win [lindex $argList 1] 1] %d,%d row col
  826.         return [${cmd}SubCmd $win $row $col 0]
  827.     }
  828.  
  829.     editwinpath {
  830.         if {$argCount != 1} {
  831.         mwutil::wrongNumArgs "$win $cmd"
  832.         }
  833.  
  834.         if {[winfo exists $data(bodyFrEd)]} {
  835.         return $data(bodyFrEd)
  836.         } else {
  837.         return ""
  838.         }
  839.     }
  840.  
  841.     entrypath {
  842.         if {$argCount != 1} {
  843.         mwutil::wrongNumArgs "$win $cmd"
  844.         }
  845.  
  846.         if {[winfo exists $data(bodyFrEd)]} {
  847.         set class [winfo class $data(bodyFrEd)]
  848.         if {[string compare $class Mentry] == 0 ||
  849.             [string compare $class Checkbutton] == 0} {
  850.             return ""
  851.         } else {
  852.             return $data(editFocus)
  853.         }
  854.         } else {
  855.         return ""
  856.         }
  857.     }
  858.  
  859.     fillcolumn {
  860.         if {$argCount != 3} {
  861.         mwutil::wrongNumArgs "$win $cmd columnIndex text"
  862.         }
  863.  
  864.         synchronize $win
  865.         set col [colIndex $win [lindex $argList 1] 1]
  866.         return [fillcolumnSubCmd $win $col [lindex $argList 2]]
  867.     }
  868.  
  869.     index {
  870.         if {$argCount != 2} {
  871.         mwutil::wrongNumArgs "$win $cmd index"
  872.         }
  873.  
  874.         synchronize $win
  875.         return [rowIndex $win [lindex $argList 1] 1]
  876.     }
  877.  
  878.     insert {
  879.         if {$argCount < 2} {
  880.         mwutil::wrongNumArgs "$win $cmd index ?item item ...?"
  881.         }
  882.  
  883.         synchronize $win
  884.         set index [rowIndex $win [lindex $argList 1] 1]
  885.         return [insertSubCmd $win $index [lrange $argList 2 end] \
  886.             $data(hasListVar)]
  887.     }
  888.  
  889.     insertcolumnlist {
  890.         if {$argCount != 3} {
  891.         mwutil::wrongNumArgs "$win $cmd columnIndex columnList"
  892.         }
  893.  
  894.         synchronize $win
  895.         set arg1 [lindex $argList 1]
  896.         if {[string first $arg1 end] == 0 || $arg1 == $data(colCount)} {
  897.         set col $data(colCount)
  898.         } else {
  899.         set col [colIndex $win $arg1 1]
  900.         }
  901.         return [insertcolumnsSubCmd $win $col [lindex $argList 2]]
  902.     }
  903.  
  904.     insertcolumns {
  905.         if {$argCount < 2} {
  906.         mwutil::wrongNumArgs "$win $cmd columnIndex\
  907.                       ?width title ?alignment?\
  908.                        width title ?alignment? ...?"
  909.         }
  910.  
  911.         synchronize $win
  912.         set arg1 [lindex $argList 1]
  913.         if {[string first $arg1 end] == 0 || $arg1 == $data(colCount)} {
  914.         set col $data(colCount)
  915.         } else {
  916.         set col [colIndex $win $arg1 1]
  917.         }
  918.         return [insertcolumnsSubCmd $win $col [lrange $argList 2 end]]
  919.     }
  920.  
  921.     insertlist {
  922.         if {$argCount != 3} {
  923.         mwutil::wrongNumArgs "$win $cmd index list"
  924.         }
  925.  
  926.         synchronize $win
  927.         set index [rowIndex $win [lindex $argList 1] 1]
  928.         return [insertSubCmd $win $index [lindex $argList 2] \
  929.             $data(hasListVar)]
  930.     }
  931.  
  932.     labelpath {
  933.         if {$argCount != 2} {
  934.         mwutil::wrongNumArgs "$win $cmd columnIndex"
  935.         }
  936.  
  937.         synchronize $win
  938.         set col [colIndex $win [lindex $argList 1] 1]
  939.         return $data(hdrTxtFrLbl)$col
  940.     }
  941.  
  942.     labels {
  943.         if {$argCount != 1} {
  944.         mwutil::wrongNumArgs "$win $cmd"
  945.         }
  946.  
  947.         set children [winfo children $data(hdrTxtFr)]
  948.         return [lrange [lsort -dictionary $children] 1 end]
  949.     }
  950.  
  951.     move {
  952.         if {$argCount != 3} {
  953.         mwutil::wrongNumArgs "$win $cmd sourceIndex targetIndex"
  954.         }
  955.  
  956.         synchronize $win
  957.         set source [rowIndex $win [lindex $argList 1] 0]
  958.         set target [rowIndex $win [lindex $argList 2] 1]
  959.         return [moveSubCmd $win $source $target]
  960.     }
  961.  
  962.     movecolumn {
  963.         if {$argCount != 3} {
  964.         mwutil::wrongNumArgs "$win $cmd sourceColumnIndex\
  965.                       targetColumnIndex"
  966.         }
  967.  
  968.         synchronize $win
  969.         set arg1 [lindex $argList 1]
  970.         set source [colIndex $win $arg1 1]
  971.         set arg2 [lindex $argList 2]
  972.         if {[string first $arg2 end] == 0 || $arg2 == $data(colCount)} {
  973.         set target $data(colCount)
  974.         } else {
  975.         set target [colIndex $win $arg2 1]
  976.         }
  977.         return [movecolumnSubCmd $win $source $target]
  978.     }
  979.  
  980.     nearest {
  981.         if {$argCount != 2} {
  982.         mwutil::wrongNumArgs "$win $cmd y"
  983.         }
  984.  
  985.         set y [lindex $argList 1]
  986.         format %d $y        ;# integer check with error message
  987.         synchronize $win
  988.         return [rowIndex $win @0,$y 0]
  989.     }
  990.  
  991.     nearestcell {
  992.         if {$argCount != 3} {
  993.         mwutil::wrongNumArgs "$win $cmd x y"
  994.         }
  995.  
  996.         set x [lindex $argList 1]
  997.         format %d $x        ;# integer check with error message
  998.         set y [lindex $argList 2]
  999.         format %d $y        ;# integer check with error message
  1000.         synchronize $win
  1001.         return [cellIndex $win @$x,$y 0]
  1002.     }
  1003.  
  1004.     nearestcolumn {
  1005.         if {$argCount != 2} {
  1006.         mwutil::wrongNumArgs "$win $cmd x"
  1007.         }
  1008.  
  1009.         set x [lindex $argList 1]
  1010.         format %d $x        ;# integer check with error message
  1011.         synchronize $win
  1012.         return [colIndex $win @$x,0 0]
  1013.     }
  1014.  
  1015.     rejectinput {
  1016.         if {$argCount != 1} {
  1017.         mwutil::wrongNumArgs "$win $cmd"
  1018.         }
  1019.  
  1020.         set data(rejected) 1
  1021.     }
  1022.  
  1023.     resetsortinfo {
  1024.         if {$argCount != 1} {
  1025.         mwutil::wrongNumArgs "$win $cmd"
  1026.         }
  1027.  
  1028.         set data(sortCol) -1
  1029.         set data(sortOrder) {}
  1030.  
  1031.         place forget $data(hdrTxtFrCanv)
  1032.         set oldArrowCol $data(arrowCol)
  1033.         set data(arrowCol) -1
  1034.         synchronize $win
  1035.         adjustColumns $win l$oldArrowCol 1
  1036.         return ""
  1037.     }
  1038.  
  1039.     rowcget {
  1040.         if {$argCount != 3} {
  1041.         mwutil::wrongNumArgs "$win $cmd index option"
  1042.         }
  1043.  
  1044.         #
  1045.         # Check the row index
  1046.         #
  1047.         synchronize $win
  1048.         set rowArg [lindex $argList 1]
  1049.         set row [rowIndex $win $rowArg 0]
  1050.         if {$row < 0 || $row > $data(lastRow)} {
  1051.         return -code error \
  1052.                "row index \"$rowArg\" out of range"
  1053.         }
  1054.  
  1055.         variable rowConfigSpecs
  1056.         set opt [mwutil::fullConfigOpt [lindex $argList 2] rowConfigSpecs]
  1057.         return [doRowCget $row $win $opt]
  1058.     }
  1059.  
  1060.     rowconfigure {
  1061.         if {$argCount < 2} {
  1062.         mwutil::wrongNumArgs "$win $cmd index ?option? ?value?\
  1063.                       ?option value ...?"
  1064.         }
  1065.  
  1066.         #
  1067.         # Check the row index
  1068.         #
  1069.         synchronize $win
  1070.         set rowArg [lindex $argList 1]
  1071.         set row [rowIndex $win $rowArg 0]
  1072.         if {$row < 0 || $row > $data(lastRow)} {
  1073.         return -code error \
  1074.                "row index \"$rowArg\" out of range"
  1075.         }
  1076.  
  1077.         variable rowConfigSpecs
  1078.         set argList [lrange $argList 2 end]
  1079.         mwutil::setConfigVals $win rowConfigSpecs rowConfigVals \
  1080.                   "tablelist::doRowCget $row" $argList
  1081.         return [mwutil::configSubCmd $win rowConfigSpecs rowConfigVals \
  1082.             "tablelist::doRowConfig $row" $argList]
  1083.     }
  1084.  
  1085.     scan {
  1086.         if {$argCount != 4} {
  1087.         mwutil::wrongNumArgs "$win $cmd mark|dragto x y"
  1088.         }
  1089.  
  1090.         set x [lindex $argList 2]
  1091.         set y [lindex $argList 3]
  1092.         format %d $x        ;# integer check with error message
  1093.         format %d $y        ;# integer check with error message
  1094.         variable scanCmdOpts
  1095.         set opt [mwutil::fullOpt "option" [lindex $argList 1] $scanCmdOpts]
  1096.         synchronize $win
  1097.         return [scanSubCmd $win $opt $x $y]
  1098.     }
  1099.  
  1100.     seecell {
  1101.         if {$argCount != 2} {
  1102.         mwutil::wrongNumArgs "$win $cmd cellIndex"
  1103.         }
  1104.  
  1105.         synchronize $win
  1106.         scan [cellIndex $win [lindex $argList 1] 1] %d,%d row col
  1107.         return [${cmd}SubCmd $win $row $col]
  1108.     }
  1109.  
  1110.     seecolumn {
  1111.         if {$argCount != 2} {
  1112.         mwutil::wrongNumArgs "$win $cmd columnIndex"
  1113.         }
  1114.  
  1115.         synchronize $win
  1116.         set col [colIndex $win [lindex $argList 1] 1]
  1117.         return [seecellSubCmd $win [rowIndex $win @0,0 0] $col]
  1118.     }
  1119.  
  1120.     selection {
  1121.         if {$argCount < 3 || $argCount > 4} {
  1122.         mwutil::wrongNumArgs "$win $cmd option firstIndex lastIndex" \
  1123.                      "$win $cmd indexList"
  1124.         }
  1125.  
  1126.         synchronize $win
  1127.         variable selCmdOpts
  1128.         set opt [mwutil::fullOpt "option" [lindex $argList 1] $selCmdOpts]
  1129.         set first [lindex $argList 2]
  1130.         switch $opt {
  1131.         anchor -
  1132.         includes {
  1133.             if {$argCount != 3} {
  1134.             mwutil::wrongNumArgs "$win selection $opt index"
  1135.             }
  1136.             set index [rowIndex $win $first 0]
  1137.             return [selectionSubCmd $win $opt $index $index]
  1138.         }
  1139.         clear -
  1140.         set {
  1141.             if {$argCount == 3} {
  1142.             foreach elem $first {
  1143.                 set index [rowIndex $win $elem 0]
  1144.                 selectionSubCmd $win $opt $index $index
  1145.             }
  1146.             return ""
  1147.             } else {
  1148.             set first [rowIndex $win $first 0]
  1149.             set last [rowIndex $win [lindex $argList 3] 0]
  1150.             return [selectionSubCmd $win $opt $first $last]
  1151.             }
  1152.         }
  1153.         }
  1154.     }
  1155.  
  1156.     separatorpath {
  1157.         if {$argCount != 2} {
  1158.         mwutil::wrongNumArgs "$win $cmd columnIndex"
  1159.         }
  1160.  
  1161.         synchronize $win
  1162.         set col [colIndex $win [lindex $argList 1] 1]
  1163.         if {$data(-showseparators)} {
  1164.         return $data(sep)$col
  1165.         } else {
  1166.         return ""
  1167.         }
  1168.     }
  1169.  
  1170.     separators {
  1171.         if {$argCount != 1} {
  1172.         mwutil::wrongNumArgs "$win $cmd"
  1173.         }
  1174.  
  1175.         set sepList {}
  1176.         foreach w [winfo children $win] {
  1177.         if {[regexp {^sep[0-9]+$} [winfo name $w]]} {
  1178.             lappend sepList $w
  1179.         }
  1180.         }
  1181.         return $sepList
  1182.     }
  1183.  
  1184.     size {
  1185.         if {$argCount != 1} {
  1186.         mwutil::wrongNumArgs "$win $cmd"
  1187.         }
  1188.  
  1189.         synchronize $win
  1190.         return $data(itemCount)
  1191.     }
  1192.  
  1193.     sort {
  1194.         if {$argCount < 1 || $argCount > 2} {
  1195.         mwutil::wrongNumArgs "$win $cmd  ?-increasing|-decreasing?"
  1196.         }
  1197.  
  1198.         if {$argCount == 1} {
  1199.         set order -increasing
  1200.         } else {
  1201.         variable sortOrders
  1202.         set order [mwutil::fullOpt "option" \
  1203.                [lindex $argList 2] $sortOrders]
  1204.         }
  1205.         synchronize $win
  1206.         return [sortSubCmd $win -1 $order]
  1207.     }
  1208.  
  1209.     sortbycolumn {
  1210.         if {$argCount < 2 || $argCount > 3} {
  1211.         mwutil::wrongNumArgs "$win $cmd columnIndex\
  1212.                       ?-increasing|-decreasing?"
  1213.         }
  1214.  
  1215.         synchronize $win
  1216.         set col [colIndex $win [lindex $argList 1] 1]
  1217.         if {$argCount == 2} {
  1218.         set order -increasing
  1219.         } else {
  1220.         variable sortOrders
  1221.         set order [mwutil::fullOpt "option" \
  1222.                [lindex $argList 2] $sortOrders]
  1223.         }
  1224.         return [sortSubCmd $win $col $order]
  1225.     }
  1226.  
  1227.     sortcolumn {
  1228.         if {$argCount != 1} {
  1229.         mwutil::wrongNumArgs "$win $cmd"
  1230.         }
  1231.  
  1232.         return $data(sortCol)
  1233.     }
  1234.  
  1235.     sortorder {
  1236.         if {$argCount != 1} {
  1237.         mwutil::wrongNumArgs "$win $cmd"
  1238.         }
  1239.  
  1240.         return $data(sortOrder)
  1241.     }
  1242.  
  1243.     xview -
  1244.     yview {
  1245.         synchronize $win
  1246.         return [${cmd}SubCmd $win [lrange $argList 1 end]]
  1247.     }
  1248.     }
  1249. }
  1250.  
  1251. #------------------------------------------------------------------------------
  1252. # tablelist::activateSubCmd
  1253. #
  1254. # This procedure is invoked to process the tablelist activate subcommand.
  1255. #------------------------------------------------------------------------------
  1256. proc tablelist::activateSubCmd {win index} {
  1257.     upvar ::tablelist::ns${win}::data data
  1258.  
  1259.     if {$data(isDisabled)} {
  1260.     return ""
  1261.     }
  1262.  
  1263.     #
  1264.     # Adjust the index to fit within the existing items
  1265.     #
  1266.     if {$index > $data(lastRow)} {
  1267.     set index $data(lastRow)
  1268.     }
  1269.     if {$index < 0} {
  1270.     set index 0
  1271.     }
  1272.  
  1273.     set data(activeIdx) $index
  1274.     return ""
  1275. }
  1276.  
  1277. #------------------------------------------------------------------------------
  1278. # tablelist::bboxSubCmd
  1279. #
  1280. # This procedure is invoked to process the tablelist bbox subcommand.
  1281. #------------------------------------------------------------------------------
  1282. proc tablelist::bboxSubCmd {win index} {
  1283.     upvar ::tablelist::ns${win}::data data
  1284.  
  1285.     set w $data(body)
  1286.     set dlineinfo [$w dlineinfo [expr {double($index + 1)}]]
  1287.     if {$data(itemCount) == 0 || [string compare $dlineinfo ""] == 0} {
  1288.     return {}
  1289.     }
  1290.  
  1291.     foreach {x y width height baselinePos} $dlineinfo {
  1292.     lappend bbox [expr {$x + [winfo x $w]}] \
  1293.              [expr {$y + [winfo y $w] + $data(-selectborderwidth)}] \
  1294.              $width [expr {$height - 2*$data(-selectborderwidth) - 1}]
  1295.     }
  1296.     return $bbox
  1297. }
  1298.  
  1299. #------------------------------------------------------------------------------
  1300. # tablelist::containingSubCmd
  1301. #
  1302. # This procedure is invoked to process the tablelist containing subcommand.
  1303. #------------------------------------------------------------------------------
  1304. proc tablelist::containingSubCmd {win y} {
  1305.     upvar ::tablelist::ns${win}::data data
  1306.  
  1307.     set row [rowIndex $win @0,$y 0]
  1308.  
  1309.     set w $data(body)
  1310.     incr y -[winfo y $w]
  1311.     set dlineinfo [$w dlineinfo [expr {double($row + 1)}]]
  1312.     if {$y < [lindex $dlineinfo 1] + [lindex $dlineinfo 3]} {
  1313.     return $row
  1314.     } else {
  1315.     return -1
  1316.     }
  1317. }
  1318.  
  1319. #------------------------------------------------------------------------------
  1320. # tablelist::containingcolumnSubCmd
  1321. #
  1322. # This procedure is invoked to process the tablelist containingcolumn
  1323. # subcommand.
  1324. #------------------------------------------------------------------------------
  1325. proc tablelist::containingcolumnSubCmd {win x} {
  1326.     upvar ::tablelist::ns${win}::data data
  1327.  
  1328.     set col [colIndex $win @$x,0 0]
  1329.     if {$col < 0} {
  1330.     return -1
  1331.     }
  1332.  
  1333.     set lbl $data(hdrTxtFrLbl)$col
  1334.     if {$x + [winfo rootx $win] < [winfo width $lbl] + [winfo rootx $lbl]} {
  1335.     return $col
  1336.     } else {
  1337.     return -1
  1338.     }
  1339. }
  1340.  
  1341. #------------------------------------------------------------------------------
  1342. # tablelist::curselectionSubCmd
  1343. #
  1344. # This procedure is invoked to process the tablelist curselection subcommand.
  1345. #------------------------------------------------------------------------------
  1346. proc tablelist::curselectionSubCmd win {
  1347.     upvar ::tablelist::ns${win}::data data
  1348.  
  1349.     #
  1350.     # Find the selected lines of the body text widget
  1351.     #
  1352.     set result {}
  1353.     set w $data(body)
  1354.     set selRange [$w tag nextrange select 1.0]
  1355.     while {[llength $selRange] != 0} {
  1356.     set selStart [lindex $selRange 0]
  1357.     set selEnd [lindex $selRange 1]
  1358.     lappend result [expr {int($selStart) - 1}]
  1359.  
  1360.     set selRange [$w tag nextrange select $selEnd]
  1361.     }
  1362.     return $result
  1363. }
  1364.  
  1365. #------------------------------------------------------------------------------
  1366. # tablelist::deleteSubCmd
  1367. #
  1368. # This procedure is invoked to process the tablelist delete subcommand.
  1369. #------------------------------------------------------------------------------
  1370. proc tablelist::deleteSubCmd {win first last argCount} {
  1371.     upvar ::tablelist::ns${win}::data data
  1372.  
  1373.     if {$data(isDisabled)} {
  1374.     return ""
  1375.     }
  1376.  
  1377.     if {$argCount == 1} {
  1378.     if {[llength $first] == 1} {            ;# just to save time
  1379.         set index [rowIndex $win [lindex $first 0] 0]
  1380.         return [deleteRows $win $index $index $data(hasListVar)]
  1381.     } elseif {$data(itemCount) == 0} {        ;# no items present
  1382.         return ""
  1383.     } else {                    ;# a bit more work
  1384.         #
  1385.         # Sort the numerical equivalents of the
  1386.         # specified indices in decreasing order
  1387.         #
  1388.         set indexList {}
  1389.         foreach elem $first {
  1390.         set index [rowIndex $win $elem 0]
  1391.         if {$index < 0} {
  1392.             set index 0
  1393.         } elseif {$index > $data(lastRow)} {
  1394.             set index $data(lastRow)
  1395.         }
  1396.         lappend indexList $index
  1397.         }
  1398.         set indexList [lsort -integer -decreasing $indexList]
  1399.  
  1400.         #
  1401.         # Traverse the sorted index list and ignore any duplicates
  1402.         #
  1403.         set prevIndex -1
  1404.         foreach index $indexList {
  1405.         if {$index != $prevIndex} {
  1406.             deleteRows $win $index $index $data(hasListVar)
  1407.             set prevIndex $index
  1408.         }
  1409.         }
  1410.         return ""
  1411.     }
  1412.     } else {
  1413.     set first [rowIndex $win $first 0]
  1414.     set last [rowIndex $win $last 0]
  1415.     return [deleteRows $win $first $last $data(hasListVar)]
  1416.     }
  1417. }
  1418.  
  1419. #------------------------------------------------------------------------------
  1420. # tablelist::deleteRows
  1421. #
  1422. # Deletes a given range of rows of a tablelist widget.
  1423. #------------------------------------------------------------------------------
  1424. proc tablelist::deleteRows {win first last updateListVar} {
  1425.     upvar ::tablelist::ns${win}::data data
  1426.  
  1427.     #
  1428.     # Adjust the range to fit within the existing items
  1429.     #
  1430.     if {$first < 0} {
  1431.     set first 0
  1432.     }
  1433.     if {$last > $data(lastRow)} {
  1434.     set last $data(lastRow)
  1435.     }
  1436.     set count [expr {$last - $first + 1}]
  1437.     if {$count <= 0} {
  1438.     return ""
  1439.     }
  1440.  
  1441.     #
  1442.     # Check whether the width of any dynamic-width
  1443.     # column might be affected by the deletion
  1444.     #
  1445.     set w $data(body)
  1446.     set itemListRange [lrange $data(itemList) $first $last]
  1447.     if {$count == $data(itemCount)} {
  1448.     set colWidthsChanged 1                ;# just to save time
  1449.     } else {
  1450.     set colWidthsChanged 0
  1451.     set snipStr $data(-snipstring)
  1452.     foreach item $itemListRange {
  1453.         set dispItem [strToDispStr $item]
  1454.         set key [lindex $item end]
  1455.         set col 0
  1456.         foreach text [lrange $dispItem 0 $data(lastCol)] \
  1457.             colFont $data(colFontList) \
  1458.             fmtCmdFlag $data(fmtCmdFlagList) \
  1459.             {pixels alignment} $data(colList) {
  1460.         if {$data($col-hide) || $pixels != 0} {
  1461.             incr col
  1462.             continue
  1463.         }
  1464.  
  1465.         if {$fmtCmdFlag} {
  1466.             set text [uplevel #0 $data($col-formatcommand) \
  1467.                   [list [lindex $item $col]]]
  1468.             set text [strToDispStr $text]
  1469.         }
  1470.         if {[info exists data($key-$col-image)]} {
  1471.             set imageWidth [image width $data($key-$col-image)]
  1472.         } else {
  1473.             set imageWidth 0
  1474.         }
  1475.         if {[info exists data($key-$col-font)]} {
  1476.             set cellFont $data($key-$col-font)
  1477.         } elseif {[info exists data($key-font)]} {
  1478.             set cellFont $data($key-font)
  1479.         } else {
  1480.             set cellFont $colFont
  1481.         }
  1482.         adjustElem $win text imageWidth $cellFont \
  1483.                $pixels $alignment $snipStr
  1484.         set textWidth [font measure $cellFont -displayof $win $text]
  1485.         set elemWidth [expr {$imageWidth + $textWidth}]
  1486.         if {$elemWidth == $data($col-elemWidth) &&
  1487.             [incr data($col-widestCount) -1] == 0} {
  1488.             set colWidthsChanged 1
  1489.             break
  1490.         }
  1491.  
  1492.         incr col
  1493.         }
  1494.  
  1495.         if {$colWidthsChanged} {
  1496.         break
  1497.         }
  1498.     }
  1499.     }
  1500.  
  1501.     #
  1502.     # Delete the given items and their tags from the body text widget.
  1503.     # Interestingly, for a large number of items it is much more efficient to
  1504.     # delete each line individually than to invoke a global delete command.
  1505.     #
  1506.     set textIdx1 [expr {double($first + 1)}]
  1507.     set textIdx2 [expr {double($first + 2)}]
  1508.     foreach item $itemListRange {
  1509.     $w delete $textIdx1 $textIdx2
  1510.  
  1511.     set key [lindex $item end]
  1512.     array set tagData [array get data $key*-\[bfs\]*]    ;# for speed
  1513.  
  1514.     foreach tag [array names tagData $key-\[bfs\]*] {
  1515.         $w tag delete $tag
  1516.         unset data($tag)
  1517.         if {[string match $key-\[bf\]* $tag]} {
  1518.         incr data(tagCount) -1
  1519.         }
  1520.     }
  1521.  
  1522.     for {set col 0} {$col < $data(colCount)} {incr col} {
  1523.         foreach tag [array names tagData $key-$col-\[bfs\]*] {
  1524.         $w tag delete $tag
  1525.         unset data($tag)
  1526.         if {[string match $key-$col-\[bf\]* $tag]} {
  1527.             incr data(tagCount) -1
  1528.         }
  1529.         }
  1530.         if {[info exists data($key-$col-image)]} {
  1531.         unset data($key-$col-image)
  1532.         incr data(imgCount) -1
  1533.         }
  1534.     }
  1535.  
  1536.     unset tagData
  1537.     }
  1538.  
  1539.     #
  1540.     # Delete the given items from the internal list
  1541.     #
  1542.     set data(itemList) [lreplace $data(itemList) $first $last]
  1543.     incr data(itemCount) -$count
  1544.     incr data(lastRow) -$count
  1545.  
  1546.     #
  1547.     # Delete the given items from the list variable if needed
  1548.     #
  1549.     if {$updateListVar} {
  1550.     trace vdelete ::$data(-listvariable) wu $data(listVarTraceCmd)
  1551.     upvar #0 $data(-listvariable) var
  1552.     set var [lreplace $var $first $last]
  1553.     trace variable ::$data(-listvariable) wu $data(listVarTraceCmd)
  1554.     }
  1555.  
  1556.     #
  1557.     # Adjust the heights of the body text widget
  1558.     # and of the listbox child, if necessary
  1559.     #
  1560.     if {$data(-height) <= 0} {
  1561.     $w configure -height $data(itemCount)
  1562.     $data(lb) configure -height $data(itemCount)
  1563.     }
  1564.  
  1565.     #
  1566.     # Adjust the columns if necessary, adjust the separators,
  1567.     # and redraw the stripes in the body text widget
  1568.     #
  1569.     if {$colWidthsChanged} {
  1570.     adjustColumns $win allCols 1
  1571.     }
  1572.     adjustSepsWhenIdle $win
  1573.     makeStripesWhenIdle $win
  1574.  
  1575.     #
  1576.     # Update the indices anchorIdx and activeIdx
  1577.     #
  1578.     if {$first <= $data(anchorIdx)} {
  1579.     incr data(anchorIdx) -$count
  1580.     if {$data(anchorIdx) < $first} {
  1581.         set data(anchorIdx) $first
  1582.     }
  1583.     }
  1584.     if {$last < $data(activeIdx)} {
  1585.     incr data(activeIdx) -$count
  1586.     } elseif {$first <= $data(activeIdx)} {
  1587.     set data(activeIdx) $first
  1588.     if {$data(activeIdx) > $data(lastRow) && $data(lastRow) >= 0} {
  1589.         set data(activeIdx) $data(lastRow)
  1590.     }
  1591.     }
  1592.  
  1593.     #
  1594.     # Update data(editRow) if the edit window is present
  1595.     #
  1596.     if {$data(editRow) >= 0} {
  1597.     set data(editRow) [lsearch $data(itemList) "* $data(editKey)"]
  1598.     }
  1599.  
  1600.     return ""
  1601. }
  1602.  
  1603. #------------------------------------------------------------------------------
  1604. # tablelist::deletecolumnsSubCmd
  1605. #
  1606. # This procedure is invoked to process the tablelist deletecolumns subcommand.
  1607. #------------------------------------------------------------------------------
  1608. proc tablelist::deletecolumnsSubCmd {win first last argCount} {
  1609.     upvar ::tablelist::ns${win}::data data
  1610.  
  1611.     if {$data(isDisabled)} {
  1612.     return ""
  1613.     }
  1614.  
  1615.     if {$argCount == 1} {
  1616.     if {[llength $first] == 1} {            ;# just to save time
  1617.         set col [colIndex $win [lindex $first 0] 1]
  1618.         deleteCols $win $col $col
  1619.         redisplay $win
  1620.     } elseif {$data(colCount) == 0} {        ;# no columns present
  1621.         return ""
  1622.     } else {                    ;# a bit more work
  1623.         #
  1624.         # Sort the numerical equivalents of the
  1625.         # specified column indices in decreasing order
  1626.         #
  1627.         set colList {}
  1628.         foreach elem $first {
  1629.         lappend colList [colIndex $win $elem 1]
  1630.         }
  1631.         set colList [lsort -integer -decreasing $colList]
  1632.  
  1633.         #
  1634.         # Traverse the sorted column index
  1635.         # list and ignore any duplicates
  1636.         #
  1637.         set deleted 0
  1638.         set prevCol -1
  1639.         foreach col $colList {
  1640.         if {$col != $prevCol} {
  1641.             deleteCols $win $col $col
  1642.             set deleted 1
  1643.             set prevCol $col
  1644.         }
  1645.         }
  1646.         if {$deleted} {
  1647.         redisplay $win
  1648.         }
  1649.     }
  1650.     } else {
  1651.     set first [colIndex $win $first 1]
  1652.     set last [colIndex $win $last 1]
  1653.     if {$first <= $last} {
  1654.         deleteCols $win $first $last
  1655.         redisplay $win
  1656.     }
  1657.     }
  1658.  
  1659.     return ""
  1660. }
  1661.  
  1662. #------------------------------------------------------------------------------
  1663. # tablelist::deleteCols
  1664. #
  1665. # Deletes a given range of columns of a tablelist widget.
  1666. #------------------------------------------------------------------------------
  1667. proc tablelist::deleteCols {win first last} {
  1668.     upvar ::tablelist::ns${win}::data data
  1669.  
  1670.     #
  1671.     # Delete the data corresponding to the given range
  1672.     #
  1673.     for {set col $first} {$col <= $last} {incr col} {
  1674.     deleteColData $win $col
  1675.     }
  1676.  
  1677.     #
  1678.     # Shift the elements of data corresponding to the column
  1679.     # indices > last to the left by last - first + 1 positions
  1680.     #
  1681.     for {set oldCol [expr {$last + 1}]; set newCol $first} \
  1682.     {$oldCol < $data(colCount)} {incr oldCol; incr newCol} {
  1683.     moveColData $win data data imgs $oldCol $newCol
  1684.     }
  1685.  
  1686.     #
  1687.     # Update the item list
  1688.     #
  1689.     set newItemList {}
  1690.     foreach item $data(itemList) {
  1691.     set item [lreplace $item $first $last]
  1692.     lappend newItemList $item
  1693.     }
  1694.     set data(itemList) $newItemList
  1695.  
  1696.     #
  1697.     # Update the list variable if present
  1698.     #
  1699.     condUpdateListVar $win
  1700.  
  1701.     #
  1702.     # Set up and adjust the columns, and rebuild
  1703.     # the lists of the column fonts and tag names
  1704.     #
  1705.     setupColumns $win \
  1706.     [lreplace $data(-columns) [expr {3*$first}] [expr {3*$last + 2}]] 1
  1707.     makeColFontAndTagLists $win
  1708.     adjustColumns $win {} 1
  1709.  
  1710.     #
  1711.     # Reconfigure the relevant column labels
  1712.     #
  1713.     for {set col $first} {$col < $data(colCount)} {incr col} {
  1714.     reconfigColLabels $win imgs $col
  1715.     }
  1716. }
  1717.  
  1718. #------------------------------------------------------------------------------
  1719. # tablelist::fillcolumnSubCmd
  1720. #
  1721. # This procedure is invoked to process the tablelist fillcolumn subcommand.
  1722. #------------------------------------------------------------------------------
  1723. proc tablelist::fillcolumnSubCmd {win colIdx text} {
  1724.     upvar ::tablelist::ns${win}::data data
  1725.  
  1726.     if {$data(isDisabled)} {
  1727.     return ""
  1728.     }
  1729.  
  1730.     #
  1731.     # Update the item list
  1732.     #
  1733.     set newItemList {}
  1734.     foreach item $data(itemList) {
  1735.     set item [lreplace $item $colIdx $colIdx $text]
  1736.     lappend newItemList $item
  1737.     }
  1738.     set data(itemList) $newItemList
  1739.  
  1740.     #
  1741.     # Update the list variable if present
  1742.     #
  1743.     condUpdateListVar $win
  1744.  
  1745.     #
  1746.     # Adjust the columns and make sure the
  1747.     # items will be redisplayed at idle time
  1748.     #
  1749.     adjustColumns $win $colIdx 1
  1750.     redisplayWhenIdle $win
  1751.     return ""
  1752. }
  1753.  
  1754. #------------------------------------------------------------------------------
  1755. # tablelist::getSubCmd
  1756. #
  1757. # This procedure is invoked to process the tablelist get subcommand.
  1758. #------------------------------------------------------------------------------
  1759. proc tablelist::getSubCmd {win first last argCount} {
  1760.     upvar ::tablelist::ns${win}::data data
  1761.  
  1762.     #
  1763.     # Get the specified items from the internal list
  1764.     #
  1765.     set result {}
  1766.     if {$argCount == 1} {
  1767.     foreach elem $first {
  1768.         set index [rowIndex $win $elem 0]
  1769.         if {$index >= 0 && $index < $data(itemCount)} {
  1770.         set item [lindex $data(itemList) $index]
  1771.         lappend result [lrange $item 0 $data(lastCol)]
  1772.         }
  1773.     }
  1774.  
  1775.     if {[llength $first] == 1} {
  1776.         return [lindex $result 0]
  1777.     } else {
  1778.         return $result
  1779.     }
  1780.     } else {
  1781.     set first [rowIndex $win $first 0]
  1782.     set last [rowIndex $win $last 0]
  1783.  
  1784.     #
  1785.     # Adjust the range to fit within the existing items
  1786.     #
  1787.     if {$first > $data(lastRow)} {
  1788.         return {}
  1789.     }
  1790.     if {$last > $data(lastRow)} {
  1791.         set last $data(lastRow)
  1792.     }
  1793.     if {$first < 0} {
  1794.         set first 0
  1795.     }
  1796.  
  1797.     foreach item [lrange $data(itemList) $first $last] {
  1798.         lappend result [lrange $item 0 $data(lastCol)]
  1799.     }
  1800.     return $result
  1801.     }
  1802. }
  1803.  
  1804. #------------------------------------------------------------------------------
  1805. # tablelist::getcolumnsSubCmd
  1806. #
  1807. # This procedure is invoked to process the tablelist getcolumns subcommand.
  1808. #------------------------------------------------------------------------------
  1809. proc tablelist::getcolumnsSubCmd {win first last argCount} {
  1810.     upvar ::tablelist::ns${win}::data data
  1811.  
  1812.     #
  1813.     # Get the specified columns from the internal list
  1814.     #
  1815.     set result {}
  1816.     if {$argCount == 1} {
  1817.     foreach elem $first {
  1818.         set col [colIndex $win $elem 1]
  1819.         set colResult {}
  1820.         foreach item $data(itemList) {
  1821.         lappend colResult [lindex $item $col]
  1822.         }
  1823.         lappend result $colResult
  1824.     }
  1825.  
  1826.     if {[llength $first] == 1} {
  1827.         return [lindex $result 0]
  1828.     } else {
  1829.         return $result
  1830.     }
  1831.     } else {
  1832.     set first [colIndex $win $first 1]
  1833.     set last [colIndex $win $last 1]
  1834.  
  1835.     if {$first > $last} {
  1836.         return {}
  1837.     }
  1838.  
  1839.     for {set col $first} {$col <= $last} {incr col} {
  1840.         set colResult {}
  1841.         foreach item $data(itemList) {
  1842.         lappend colResult [lindex $item $col]
  1843.         }
  1844.         lappend result $colResult
  1845.     }
  1846.     return $result
  1847.     }
  1848. }
  1849.  
  1850. #------------------------------------------------------------------------------
  1851. # tablelist::getkeysSubCmd
  1852. #
  1853. # This procedure is invoked to process the tablelist getkeys subcommand.
  1854. #------------------------------------------------------------------------------
  1855. proc tablelist::getkeysSubCmd {win first last argCount} {
  1856.     upvar ::tablelist::ns${win}::data data
  1857.  
  1858.     #
  1859.     # Get the specified keys from the internal list
  1860.     #
  1861.     set result {}
  1862.     if {$argCount == 1} {
  1863.     foreach elem $first {
  1864.         set index [rowIndex $win $elem 0]
  1865.         if {$index >= 0 && $index < $data(itemCount)} {
  1866.         set item [lindex $data(itemList) $index]
  1867.         lappend result [string range [lindex $item end] 1 end]
  1868.         }
  1869.     }
  1870.  
  1871.     if {[llength $first] == 1} {
  1872.         return [lindex $result 0]
  1873.     } else {
  1874.         return $result
  1875.     }
  1876.     } else {
  1877.     set first [rowIndex $win $first 0]
  1878.     set last [rowIndex $win $last 0]
  1879.  
  1880.     #
  1881.     # Adjust the range to fit within the existing items
  1882.     #
  1883.     if {$first > $data(lastRow)} {
  1884.         return {}
  1885.     }
  1886.     if {$last > $data(lastRow)} {
  1887.         set last $data(lastRow)
  1888.     }
  1889.     if {$first < 0} {
  1890.         set first 0
  1891.     }
  1892.  
  1893.     foreach item [lrange $data(itemList) $first $last] {
  1894.         lappend result [string range [lindex $item end] 1 end]
  1895.     }
  1896.     return $result
  1897.     }
  1898. }
  1899.  
  1900. #------------------------------------------------------------------------------
  1901. # tablelist::insertSubCmd
  1902. #
  1903. # This procedure is invoked to process the tablelist insert and insertlist
  1904. # subcommands.
  1905. #------------------------------------------------------------------------------
  1906. proc tablelist::insertSubCmd {win index argList updateListVar} {
  1907.     upvar ::tablelist::ns${win}::data data
  1908.  
  1909.     if {$data(isDisabled)} {
  1910.     return ""
  1911.     }
  1912.  
  1913.     set argCount [llength $argList]
  1914.     if {$argCount == 0} {
  1915.     return ""
  1916.     }
  1917.  
  1918.     if {$index < 0} {
  1919.     set index 0
  1920.     }
  1921.  
  1922.     #
  1923.     # Insert the items into the body text widget and into the internal list
  1924.     #
  1925.     set w $data(body)
  1926.     set widgetFont $data(-font)
  1927.     set snipStr $data(-snipstring)
  1928.     set savedCount $data(itemCount)
  1929.     set colWidthsChanged 0
  1930.     set idx $index
  1931.     set line [expr {$index + 1}]
  1932.     foreach item $argList {
  1933.     set item [adjustItem $item $data(colCount)]
  1934.     if {$data(itemCount) != 0} {
  1935.         $w insert $line.0 \n
  1936.     }
  1937.     set col 0
  1938.  
  1939.     if {$data(hasColTags)} {
  1940.         set insertArgs {}
  1941.         foreach text [strToDispStr $item] \
  1942.             colFont $data(colFontList) \
  1943.             colTags $data(colTagsList) \
  1944.             fmtCmdFlag $data(fmtCmdFlagList) \
  1945.             {pixels alignment} $data(colList) {
  1946.         if {$data($col-hide)} {
  1947.             incr col
  1948.             continue
  1949.         }
  1950.  
  1951.         #
  1952.         # Update the column width or clip the element if necessary
  1953.         #
  1954.         if {$fmtCmdFlag} {
  1955.             set text [uplevel #0 $data($col-formatcommand) \
  1956.                   [list [lindex $item $col]]]
  1957.             set text [strToDispStr $text]
  1958.         }
  1959.         if {$pixels == 0} {        ;# convention: dynamic width
  1960.             set textWidth \
  1961.             [font measure $colFont -displayof $win $text]
  1962.             if {$data($col-maxPixels) > 0 &&
  1963.             $textWidth > $data($col-maxPixels)} {
  1964.             set pixels $data($col-maxPixels)
  1965.             }
  1966.             if {$textWidth == $data($col-elemWidth)} {
  1967.             incr data($col-widestCount)
  1968.             } elseif {$textWidth > $data($col-elemWidth)} {
  1969.             set data($col-elemWidth) $textWidth
  1970.             set data($col-widestCount) 1
  1971.             if {$textWidth > $data($col-reqPixels)} {
  1972.                 set data($col-reqPixels) $textWidth
  1973.                 if {$pixels == 0} {
  1974.                 set colWidthsChanged 1
  1975.                 }
  1976.             }
  1977.             }
  1978.         }
  1979.         if {$pixels != 0} {
  1980.             incr pixels $data($col-delta)
  1981.             set text [strRangeExt $win $text $colFont \
  1982.                   $pixels $alignment $snipStr]
  1983.         }
  1984.  
  1985.         lappend insertArgs \t$text\t $colTags
  1986.         incr col
  1987.         }
  1988.  
  1989.         #
  1990.         # Insert the item into the body text widget
  1991.         #
  1992.         if {[llength $insertArgs] != 0} {
  1993.         eval [list $w insert $line.0] $insertArgs
  1994.         }
  1995.  
  1996.     } else {
  1997.         set insertStr ""
  1998.         foreach text [strToDispStr $item] \
  1999.             fmtCmdFlag $data(fmtCmdFlagList) \
  2000.             {pixels alignment} $data(colList) {
  2001.         if {$data($col-hide)} {
  2002.             incr col
  2003.             continue
  2004.         }
  2005.  
  2006.         #
  2007.         # Update the column width or clip the element if necessary
  2008.         #
  2009.         if {$fmtCmdFlag} {
  2010.             set text [uplevel #0 $data($col-formatcommand) \
  2011.                   [list [lindex $item $col]]]
  2012.             set text [strToDispStr $text]
  2013.         }
  2014.         if {$pixels == 0} {        ;# convention: dynamic width
  2015.             set textWidth \
  2016.             [font measure $widgetFont -displayof $win $text]
  2017.             if {$data($col-maxPixels) > 0 &&
  2018.             $textWidth > $data($col-maxPixels)} {
  2019.             set pixels $data($col-maxPixels)
  2020.             }
  2021.             if {$textWidth == $data($col-elemWidth)} {
  2022.             incr data($col-widestCount)
  2023.             } elseif {$textWidth > $data($col-elemWidth)} {
  2024.             set data($col-elemWidth) $textWidth
  2025.             set data($col-widestCount) 1
  2026.             if {$textWidth > $data($col-reqPixels)} {
  2027.                 set data($col-reqPixels) $textWidth
  2028.                 if {$pixels == 0} {
  2029.                 set colWidthsChanged 1
  2030.                 }
  2031.             }
  2032.             }
  2033.         }
  2034.         if {$pixels != 0} {
  2035.             incr pixels $data($col-delta)
  2036.             set text [strRangeExt $win $text $widgetFont \
  2037.                   $pixels $alignment $snipStr]
  2038.         }
  2039.  
  2040.         append insertStr \t$text\t
  2041.         incr col
  2042.         }
  2043.  
  2044.         #
  2045.         # Insert the item into the body text widget
  2046.         #
  2047.         $w insert $line.0 $insertStr
  2048.     }
  2049.  
  2050.     #
  2051.     # Insert the item into the list variable if needed
  2052.     #
  2053.     if {$updateListVar} {
  2054.         trace vdelete ::$data(-listvariable) wu $data(listVarTraceCmd)
  2055.         upvar #0 $data(-listvariable) var
  2056.         if {$idx == $data(itemCount)} {
  2057.         lappend var $item        ;# this works much faster
  2058.         } else {
  2059.         set var [linsert $var $idx $item]
  2060.         }
  2061.         trace variable ::$data(-listvariable) wu $data(listVarTraceCmd)
  2062.     }
  2063.  
  2064.     #
  2065.     # Insert the item into the internal list
  2066.     #
  2067.     lappend item k[incr data(seqNum)]
  2068.     if {$idx == $data(itemCount)} {
  2069.         lappend data(itemList) $item    ;# this works much faster
  2070.     } else {
  2071.         set data(itemList) [linsert $data(itemList) $idx $item]
  2072.     }
  2073.  
  2074.     incr idx
  2075.     incr line
  2076.     incr data(itemCount)
  2077.     }
  2078.     set data(lastRow) [expr {$data(itemCount) - 1}]
  2079.  
  2080.     #
  2081.     # Adjust the heights of the body text widget
  2082.     # and of the listbox child, if necessary
  2083.     #
  2084.     if {$data(-height) <= 0} {
  2085.     $w configure -height $data(itemCount)
  2086.     $data(lb) configure -height $data(itemCount)
  2087.     }
  2088.  
  2089.     #
  2090.     # Adjust the horizontal view in the body text 
  2091.     # widget if the tablelist was previously empty
  2092.     #
  2093.     if {$savedCount == 0} {
  2094.     $w xview moveto [lindex [$data(hdrTxt) xview] 0]
  2095.     }
  2096.  
  2097.     #
  2098.     # Adjust the columns if necessary, adjust the separators,
  2099.     # and redraw the stripes in the body text widget
  2100.     #
  2101.     if {$colWidthsChanged} {
  2102.     adjustColumns $win {} 1
  2103.     }
  2104.     adjustSepsWhenIdle $win
  2105.     makeStripesWhenIdle $win
  2106.  
  2107.     #
  2108.     # Update the indices anchorIdx and activeIdx
  2109.     #
  2110.     if {$index <= $data(anchorIdx)} {
  2111.     incr data(anchorIdx) $argCount
  2112.     }
  2113.     if {$index <= $data(activeIdx)} {
  2114.     incr data(activeIdx) $argCount
  2115.     if {$data(activeIdx) > $data(lastRow) && $data(lastRow) >= 0} {
  2116.         set data(activeIdx) $data(lastRow)
  2117.     }
  2118.     }
  2119.  
  2120.     #
  2121.     # Update data(editRow) if the edit window is present
  2122.     #
  2123.     if {$data(editRow) >= 0} {
  2124.     set data(editRow) [lsearch $data(itemList) "* $data(editKey)"]
  2125.     }
  2126.  
  2127.     return ""
  2128. }
  2129.  
  2130. #------------------------------------------------------------------------------
  2131. # tablelist::insertcolumnsSubCmd
  2132. #
  2133. # This procedure is invoked to process the tablelist insertcolumns and
  2134. # insertcolumnlist subcommands.
  2135. #------------------------------------------------------------------------------
  2136. proc tablelist::insertcolumnsSubCmd {win colIdx argList} {
  2137.     variable alignments
  2138.     upvar ::tablelist::ns${win}::data data
  2139.  
  2140.     if {$data(isDisabled)} {
  2141.     return ""
  2142.     }
  2143.  
  2144.     #
  2145.     # Check the syntax of argList and get the number of columns to be inserted
  2146.     #
  2147.     set count 0
  2148.     set argCount [llength $argList]
  2149.     for {set n 0} {$n < $argCount} {incr n} {
  2150.     #
  2151.     # Check the column width
  2152.     #
  2153.     format %d [lindex $argList $n]    ;# integer check with error message
  2154.  
  2155.     #
  2156.     # Check whether the column title is present
  2157.     #
  2158.     if {[incr n] == $argCount} {
  2159.         return -code error "column title missing"
  2160.     }
  2161.  
  2162.     #
  2163.     # Check the column alignment
  2164.     #
  2165.     set alignment left
  2166.     if {[incr n] < $argCount} {
  2167.         set next [lindex $argList $n]
  2168.         if {[catch {format %d $next}] == 0} {    ;# integer check
  2169.         incr n -1
  2170.         } else {
  2171.         mwutil::fullOpt "alignment" $next $alignments
  2172.         }
  2173.     }
  2174.  
  2175.     incr count
  2176.     }
  2177.  
  2178.     #
  2179.     # Shift the elements of data corresponding to the column
  2180.     # indices >= colIdx to the right by count positions
  2181.     #
  2182.     for {set oldCol $data(lastCol); set newCol [expr {$oldCol + $count}]} \
  2183.     {$oldCol >= $colIdx} {incr oldCol -1; incr newCol -1} {
  2184.     moveColData $win data data imgs $oldCol $newCol
  2185.     }
  2186.  
  2187.     #
  2188.     # Update the item list
  2189.     #
  2190.     set emptyStrs {}
  2191.     for {set n 0} {$n < $count} {incr n} {
  2192.     lappend emptyStrs ""
  2193.     }
  2194.     set newItemList {}
  2195.     foreach item $data(itemList) {
  2196.     set item [eval [list linsert $item $colIdx] $emptyStrs]
  2197.     lappend newItemList $item
  2198.     }
  2199.     set data(itemList) $newItemList
  2200.  
  2201.     #
  2202.     # Update the list variable if present
  2203.     #
  2204.     condUpdateListVar $win
  2205.  
  2206.     #
  2207.     # Set up and adjust the columns, and rebuild
  2208.     # the lists of the column fonts and tag names
  2209.     #
  2210.     setupColumns $win \
  2211.     [eval [list linsert $data(-columns) [expr {3*$colIdx}]] $argList] 1
  2212.     makeColFontAndTagLists $win
  2213.     set limit [expr {$colIdx + $count}]
  2214.     set cols {}
  2215.     for {set col $colIdx} {$col < $limit} {incr col} {
  2216.     lappend cols $col
  2217.     }
  2218.     adjustColumns $win $cols 1
  2219.  
  2220.     #
  2221.     # Reconfigure the relevant column labels
  2222.     #
  2223.     for {set col $limit} {$col < $data(colCount)} {incr col} {
  2224.     reconfigColLabels $win imgs $col
  2225.     }
  2226.  
  2227.     #
  2228.     # Redisplay the columns
  2229.     #
  2230.     redisplay $win
  2231.     return ""
  2232. }
  2233.  
  2234. #------------------------------------------------------------------------------
  2235. # tablelist::scanSubCmd
  2236. #
  2237. # This procedure is invoked to process the tablelist scan subcommand.
  2238. #------------------------------------------------------------------------------
  2239. proc tablelist::scanSubCmd {win opt x y} {
  2240.     upvar ::tablelist::ns${win}::data data
  2241.  
  2242.     set w $data(body)
  2243.     incr x -[winfo x $w]
  2244.     incr y -[winfo y $w]
  2245.  
  2246.     $w scan $opt $x $y
  2247.     $data(hdrTxt) scan $opt $x $y
  2248.     return ""
  2249. }
  2250.  
  2251. #------------------------------------------------------------------------------
  2252. # tablelist::seeSubCmd
  2253. #
  2254. # This procedure is invoked to process the tablelist see subcommand.
  2255. #------------------------------------------------------------------------------
  2256. proc tablelist::seeSubCmd {win index} {
  2257.     upvar ::tablelist::ns${win}::data data
  2258.  
  2259.     #
  2260.     # Adjust the view in the body text widget
  2261.     #
  2262.     set w $data(body)
  2263.     set fraction [lindex [$w xview] 0]
  2264.     $w see [expr {double($index + 1)}]
  2265.     $w xview moveto $fraction
  2266.     return ""
  2267. }
  2268.  
  2269. #------------------------------------------------------------------------------
  2270. # tablelist::seecellSubCmd
  2271. #
  2272. # This procedure is invoked to process the tablelist seecell subcommand.
  2273. #------------------------------------------------------------------------------
  2274. proc tablelist::seecellSubCmd {win row col} {
  2275.     upvar ::tablelist::ns${win}::data data
  2276.  
  2277.     if {$data($col-hide)} {
  2278.     return ""
  2279.     }
  2280.  
  2281.     set alignment [lindex $data(colList) [expr {2*$col + 1}]]
  2282.     set w $data(body)
  2283.     findCellTabs $win [expr {$row + 1}] $col tabIdx1 tabIdx2
  2284.     set nextIdx [$w index $tabIdx2+1c]
  2285.  
  2286.     if {[string compare $alignment right] == 0} {
  2287.     $w see $nextIdx
  2288.  
  2289.     #
  2290.     # Shift the view in the body text widget until the first tab
  2291.     # becomes visible but finish the scrolling before the character
  2292.     # (\t or \n) at the position nextIdx would become invisible
  2293.     #
  2294.     if {![isCharVisible $w $tabIdx1]} {
  2295.         while 1 {
  2296.         $w xview scroll -1 units
  2297.         if {![isCharVisible $w $nextIdx]} {
  2298.             $w xview scroll 1 units
  2299.             break
  2300.         } elseif {[isCharVisible $w $tabIdx1]} {
  2301.             break
  2302.         }
  2303.         }
  2304.     }
  2305.     } else {
  2306.     $w see $tabIdx1
  2307.  
  2308.     #
  2309.     # Shift the view in the body text widget until the character
  2310.     # (\t or \n) at the position nextIdx becomes visible but finish
  2311.     # the scrolling before the first tab would become invisible
  2312.     #
  2313.     if {![isCharVisible $w $nextIdx]} {
  2314.         while 1 {
  2315.         $w xview scroll 1 units
  2316.         if {![isCharVisible $w $tabIdx1]} {
  2317.             $w xview scroll -1 units
  2318.             break
  2319.         } elseif {[isCharVisible $w $nextIdx]} {
  2320.             break
  2321.         }
  2322.         }
  2323.     }
  2324.     }
  2325.  
  2326.     $data(hdrTxt) xview moveto [lindex [$w xview] 0]
  2327.     return ""
  2328. }
  2329.  
  2330. #------------------------------------------------------------------------------
  2331. # tablelist::selectionSubCmd
  2332. #
  2333. # This procedure is invoked to process the tablelist selection subcommand.
  2334. #------------------------------------------------------------------------------
  2335. proc tablelist::selectionSubCmd {win opt first last} {
  2336.     upvar ::tablelist::ns${win}::data data
  2337.  
  2338.     if {$data(isDisabled) && [string compare $opt includes] != 0} {
  2339.     return ""
  2340.     }
  2341.  
  2342.     switch $opt {
  2343.     anchor {
  2344.         #
  2345.         # Adjust the index to fit within the existing items
  2346.         #
  2347.         if {$first > $data(lastRow)} {
  2348.         set first $data(lastRow)
  2349.         }
  2350.         if {$first < 0} {
  2351.         set first 0
  2352.         }
  2353.  
  2354.         set data(anchorIdx) $first
  2355.         return ""
  2356.     }
  2357.  
  2358.     clear {
  2359.         #
  2360.         # Swap the indices if necessary
  2361.         #
  2362.         if {$last < $first} {
  2363.         set tmp $first
  2364.         set first $last
  2365.         set last $tmp
  2366.         }
  2367.  
  2368.         #
  2369.         # Find the selected lines of the body text widget
  2370.         # in the text range specified by the two indices
  2371.         #
  2372.         set w $data(body)
  2373.         set firstTextIdx [expr {$first + 1}].0
  2374.         set lastTextIdx [expr {$last + 1}].end
  2375.         set selRange [$w tag nextrange select $firstTextIdx $lastTextIdx]
  2376.         while {[llength $selRange] != 0} {
  2377.         set selStart [lindex $selRange 0]
  2378.         set selEnd [lindex $selRange 1]
  2379.  
  2380.         $w tag remove select $selStart $selEnd
  2381.  
  2382.         #
  2383.         # Handle the -(select)background and -(select)foreground cell
  2384.         # and column configuration options for each element of the row
  2385.         #
  2386.         set item [lindex $data(itemList) [expr {int($selStart) - 1}]]
  2387.         set key [lindex $item end]
  2388.         set textIdx1 $selStart
  2389.         for {set col 0} {$col < $data(colCount)} {incr col} {
  2390.             if {$data($col-hide)} {
  2391.             continue
  2392.             }
  2393.  
  2394.             set textIdx2 \
  2395.             [$w search \t $textIdx1+1c "$selStart lineend"]+1c
  2396.             foreach optTail {background foreground} {
  2397.             foreach tag [list $col-select$optTail \
  2398.                      $key-select$optTail \
  2399.                      $key-$col-select$optTail] {
  2400.                 if {[info exists data($tag)]} {
  2401.                 $w tag remove $tag $textIdx1 $textIdx2
  2402.                 }
  2403.             }
  2404.             foreach tag [list $col-$optTail $key-$optTail \
  2405.                      $key-$col-$optTail] {
  2406.                 if {[info exists data($tag)]} {
  2407.                 $w tag add $tag $textIdx1 $textIdx2
  2408.                 }
  2409.             }
  2410.             }
  2411.             set textIdx1 $textIdx2
  2412.         }
  2413.  
  2414.         set selRange [$w tag nextrange select $selEnd $lastTextIdx]
  2415.         }
  2416.  
  2417.         return ""
  2418.     }
  2419.  
  2420.     includes {
  2421.         set tagNames [$data(body) tag names [expr {double($first + 1)}]]
  2422.         if {[lsearch -exact $tagNames select] >= 0} {
  2423.         return 1
  2424.         } else {
  2425.         return 0
  2426.         }
  2427.     }
  2428.  
  2429.     set {
  2430.         #
  2431.         # Swap the indices if necessary and adjust
  2432.         # the range to fit within the existing items
  2433.         #
  2434.         if {$last < $first} {
  2435.         set tmp $first
  2436.         set first $last
  2437.         set last $tmp
  2438.         }
  2439.         if {$first < 0} {
  2440.         set first 0
  2441.         }
  2442.         if {$last > $data(lastRow)} {
  2443.         set last $data(lastRow)
  2444.         }
  2445.  
  2446.         set w $data(body)
  2447.         for {set idx $first; set line [expr {$first + 1}]} \
  2448.         {$idx <= $last} {incr idx; incr line} {
  2449.         #
  2450.         # Nothing to do if the row is already selected
  2451.         #
  2452.         if {[lsearch -exact [$w tag names $line.0] select] >= 0} {
  2453.             continue
  2454.         }
  2455.  
  2456.         #
  2457.         # Check whether the row is selectable
  2458.         #
  2459.         set item [lindex $data(itemList) $idx]
  2460.         set key [lindex $item end]
  2461.         if {[info exists data($key-selectable)]} {    ;# not selectable
  2462.             continue
  2463.         }
  2464.  
  2465.         $w tag add select $line.0 $line.end
  2466.  
  2467.         #
  2468.         # Handle the -(select)background and -(select)foreground cell
  2469.         # and column configuration options for each element of the row
  2470.         #
  2471.         set textIdx1 $line.0
  2472.         for {set col 0} {$col < $data(colCount)} {incr col} {
  2473.             if {$data($col-hide)} {
  2474.             continue
  2475.             }
  2476.  
  2477.             set textIdx2 [$w search \t $textIdx1+1c $line.end]+1c
  2478.             foreach optTail {background foreground} {
  2479.             foreach tag [list $col-select$optTail \
  2480.                      $key-select$optTail \
  2481.                      $key-$col-select$optTail] {
  2482.                 if {[info exists data($tag)]} {
  2483.                 $w tag add $tag $textIdx1 $textIdx2
  2484.                 }
  2485.             }
  2486.             foreach tag [list $col-$optTail $key-$optTail \
  2487.                      $key-$col-$optTail] {
  2488.                 if {[info exists data($tag)]} {
  2489.                 $w tag remove $tag $textIdx1 $textIdx2
  2490.                 }
  2491.             }
  2492.             }
  2493.             set textIdx1 $textIdx2
  2494.         }
  2495.         }
  2496.  
  2497.         #
  2498.         # If the selection is exported and there are any selected
  2499.         # rows in the widget then make win the new owner of the
  2500.         # PRIMARY selection and register a callback to be invoked
  2501.         # when it loses ownership of the PRIMARY selection
  2502.         #
  2503.         if {$data(-exportselection) &&
  2504.         [llength [$w tag nextrange select 1.0]] != 0} {
  2505.         selection own -command \
  2506.             [list ::tablelist::lostSelection $win] $win
  2507.         }
  2508.  
  2509.         return ""
  2510.     }
  2511.     }
  2512. }
  2513.  
  2514. #------------------------------------------------------------------------------
  2515. # tablelist::xviewSubCmd
  2516. #
  2517. # This procedure is invoked to process the tablelist xview subcommand.
  2518. #------------------------------------------------------------------------------
  2519. proc tablelist::xviewSubCmd {win argList} {
  2520.     variable winSys
  2521.     upvar ::tablelist::ns${win}::data data
  2522.  
  2523.     switch [llength $argList] {
  2524.     0 {
  2525.         #
  2526.         # Command: $win xview
  2527.         #
  2528.         return [$data(hdrTxt) xview]
  2529.     }
  2530.  
  2531.     1 {
  2532.         #
  2533.         # Command: $win xview units
  2534.         #
  2535.         set units [lindex $argList 0]
  2536.         format %d $units        ;# integer check with error message
  2537.         foreach w [list $data(hdrTxt) $data(body)] {
  2538.         $w xview moveto 0
  2539.         $w xview scroll $units units
  2540.         }
  2541.         if {[string compare $winSys aqua] == 0} {
  2542.         update            ;# because of a Tk bug on Mac OS X Aqua
  2543.         }
  2544.         return ""
  2545.     }
  2546.  
  2547.     default {
  2548.         #
  2549.         # Command: $win xview moveto fraction
  2550.         #           $win xview scroll number what
  2551.         #
  2552.         foreach w [list $data(hdrTxt) $data(body)] {
  2553.         eval [list $w xview] $argList
  2554.         }
  2555.         if {[string compare $winSys aqua] == 0} {
  2556.         update            ;# because of a Tk bug on Mac OS X Aqua
  2557.         }
  2558.         return ""
  2559.     }
  2560.     }
  2561. }
  2562.  
  2563. #------------------------------------------------------------------------------
  2564. # tablelist::yviewSubCmd
  2565. #
  2566. # This procedure is invoked to process the tablelist yview subcommand.
  2567. #------------------------------------------------------------------------------
  2568. proc tablelist::yviewSubCmd {win argList} {
  2569.     upvar ::tablelist::ns${win}::data data
  2570.     variable winSys
  2571.  
  2572.     set w $data(body)
  2573.     set argCount [llength $argList]
  2574.     switch $argCount {
  2575.     0 {
  2576.         #
  2577.         # Command: $win yview
  2578.         #
  2579.         return [$w yview]
  2580.     }
  2581.  
  2582.     1 {
  2583.         #
  2584.         # Command: $win yview index
  2585.         #
  2586.         set index [rowIndex $win [lindex $argList 0] 0]
  2587.         $w yview $index
  2588.         $w xview moveto [lindex [$w xview] 0]
  2589.         if {[string compare $winSys aqua] == 0} {
  2590.         update            ;# because of a Tk bug on Mac OS X Aqua
  2591.         }
  2592.         return ""
  2593.     }
  2594.  
  2595.     default {
  2596.         #
  2597.         # Command: $win yview moveto fraction
  2598.         #           $win yview scroll number what
  2599.         #
  2600.         set opt [lindex $argList 0]
  2601.         if {[string first $opt moveto] == 0} {
  2602.         eval [list $w yview] $argList
  2603.         } elseif {[string first $opt scroll] == 0} {
  2604.         if {$argCount != 3} {
  2605.             #
  2606.             # Let Tk report the error
  2607.             #
  2608.             return [eval [list $w yview] $argList]
  2609.         }
  2610.  
  2611.         set number [lindex $argList 1]
  2612.         set number [format %d $number]    ;# integer check with error msg
  2613.         set what [lindex $argList 2]
  2614.         if {[string first $what units] == 0} {
  2615.             $w yview scroll $number units
  2616.         } elseif {[string first $what pages] == 0} {
  2617.             if {$number < 0} {
  2618.             $w yview scroll $number pages
  2619.             } else {
  2620.             #
  2621.             # The following loop is needed because "$w yview scroll
  2622.             # $number pages" doesn't produce the expected effect.
  2623.             #
  2624.             for {set n 0} {$n < $number} {incr n} {
  2625.                 $w yview scroll 1 pages
  2626.                 if {[lindex [$w yview] 1] < 1.0} {
  2627.                 $w yview scroll -1 units
  2628.                 }
  2629.             }
  2630.             }
  2631.         } else {
  2632.             #
  2633.             # Let Tk report the error
  2634.             #
  2635.             return [eval [list $w yview] $argList]
  2636.         }
  2637.         } else {
  2638.         return -code error \
  2639.                "unknown option \"$opt\": must be moveto or scroll"
  2640.         }
  2641.         if {[string compare $winSys aqua] == 0} {
  2642.         update            ;# because of a Tk bug on Mac OS X Aqua
  2643.         }
  2644.         return ""
  2645.     }
  2646.     }
  2647. }
  2648.  
  2649. #
  2650. # Private callback procedures
  2651. # ===========================
  2652. #
  2653.  
  2654. #------------------------------------------------------------------------------
  2655. # tablelist::fetchSelection
  2656. #
  2657. # This procedure is invoked when the PRIMARY selection is owned by the
  2658. # tablelist widget win and someone attempts to retrieve it as a STRING.  It
  2659. # returns part or all of the selection, as given by offset and maxChars.  The
  2660. # string which is to be (partially) returned is built by joining all of the
  2661. # visible elements of the selected rows together with tabs and the rows
  2662. # themselves with newlines.
  2663. #------------------------------------------------------------------------------
  2664. proc tablelist::fetchSelection {win offset maxChars} {
  2665.     upvar ::tablelist::ns${win}::data data
  2666.  
  2667.     if {!$data(-exportselection)} {
  2668.     return ""
  2669.     }
  2670.  
  2671.     set selection ""
  2672.     set gotItem 0
  2673.     foreach idx [curselectionSubCmd $win] {
  2674.     if {$gotItem} {
  2675.         append selection \n
  2676.     }
  2677.  
  2678.     set item [lindex $data(itemList) $idx]
  2679.     set gotText 0
  2680.     for {set col 0} {$col < $data(colCount)} {incr col} {
  2681.         if {$data($col-hide)} {
  2682.         continue
  2683.         }
  2684.  
  2685.         set text [lindex $item $col]
  2686.         if {[info exists data($col-formatcommand)]} {
  2687.         set text [uplevel #0 $data($col-formatcommand) [list $text]]
  2688.         }
  2689.  
  2690.         if {$gotText} {
  2691.         append selection \t
  2692.         }
  2693.         append selection $text
  2694.  
  2695.         set gotText 1
  2696.     }
  2697.  
  2698.     set gotItem 1
  2699.     }
  2700.  
  2701.     return [string range $selection $offset [expr {$offset + $maxChars - 1}]]
  2702. }
  2703.  
  2704. #------------------------------------------------------------------------------
  2705. # tablelist::lostSelection
  2706. #
  2707. # This procedure is invoked when the tablelist widget win loses ownership of
  2708. # the PRIMARY selection.  It deselects all items of the widget with the aid of
  2709. # the selectionSubCmd procedure if the selection is exported.
  2710. #------------------------------------------------------------------------------
  2711. proc tablelist::lostSelection win {
  2712.     upvar ::tablelist::ns${win}::data data
  2713.  
  2714.     if {$data(-exportselection)} {
  2715.     selectionSubCmd $win clear 0 $data(lastRow)
  2716.     }
  2717. }
  2718.  
  2719. #------------------------------------------------------------------------------
  2720. # tablelist::activeIdxTrace
  2721. #
  2722. # This procedure is executed whenever the array element data(activeIdx) is
  2723. # written.  It moves the "active" tag to the line that displays the active
  2724. # element of the widget in its body text child if the latter has the focus.
  2725. #------------------------------------------------------------------------------
  2726. proc tablelist::activeIdxTrace {win varName index op} {
  2727.     upvar ::tablelist::ns${win}::data data
  2728.  
  2729.     set w $data(body)
  2730.     if {$data(ownsFocus)} {
  2731.     set line [expr {$data(oldActiveIdx) + 1}]
  2732.     $w tag remove active $line.0 $line.end
  2733.  
  2734.     set line [expr {$data(activeIdx) + 1}]
  2735.     $w tag add active $line.0 $line.end
  2736.     }
  2737.  
  2738.     set data(oldActiveIdx) $data(activeIdx)
  2739. }
  2740.  
  2741. #------------------------------------------------------------------------------
  2742. # tablelist::listVarTrace
  2743. #
  2744. # This procedure is executed whenever the global variable specified by varName
  2745. # is written or unset.  It makes sure that the contents of the widget will be
  2746. # synchronized with the value of the variable at idle time, and that the
  2747. # variable is recreated if it was unset.
  2748. #------------------------------------------------------------------------------
  2749. proc tablelist::listVarTrace {win varName index op} {
  2750.     upvar ::tablelist::ns${win}::data data
  2751.  
  2752.     switch $op {
  2753.     w {
  2754.         if {![info exists data(syncId)]} {
  2755.         #
  2756.         # Arrange for the contents of the widget to be synchronized
  2757.         # with the value of the variable ::$varName at idle time
  2758.         #
  2759.         set data(syncId) [after idle [list tablelist::synchronize $win]]
  2760.  
  2761.         #
  2762.         # Cancel the execution of all delayed redisplay
  2763.         # commands, to make sure that the synchronize command
  2764.         # will be invoked first; the latter will then schedule
  2765.         # a redisplay command for execution at idle time
  2766.         #
  2767.         if {[info exists data(redispId)]} {
  2768.             after cancel $data(redispId)
  2769.         }
  2770.         }
  2771.     }
  2772.  
  2773.     u {
  2774.         #
  2775.         # Recreate the variable ::$varName by setting it according to
  2776.         # the value of data(itemList), and set the trace on it again
  2777.         #
  2778.         if {[string compare $index ""] != 0} {
  2779.         set varName ${varName}($index)
  2780.         }
  2781.         set ::$varName {}
  2782.         foreach item $data(itemList) {
  2783.         lappend ::$varName [lrange $item 0 $data(lastCol)]
  2784.         }
  2785.         trace variable ::$varName wu $data(listVarTraceCmd)
  2786.     }
  2787.     }
  2788. }
  2789.  
  2790. #
  2791. # Private procedures used in bindings
  2792. # ===================================
  2793. #
  2794. # See the module "tablelistBind.tcl".
  2795. #
  2796.  
  2797. #
  2798. # Private utility procedures
  2799. # ==========================
  2800. #
  2801. # See the module "tablelistUtil.tcl"
  2802. #
  2803.